semver#SemVer TypeScript Examples

The following examples show how to use semver#SemVer. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: windows-links.test.ts    From cuda-toolkit with MIT License 6 votes vote down vote up
test.concurrent('Windows Cuda versions in descending order', async () => {
  const wLinks: AbstractLinks = WindowsLinks.Instance
  const versions = wLinks.getAvailableLocalCudaVersions()
  for (let i = 0; i < versions.length - 1; i++) {
    const versionA: SemVer = versions[i]
    const versionB: SemVer = versions[i + 1]
    expect(versionA.compare(versionB)).toBe(1) // A should be greater than B
  }
})
Example #2
Source File: app.component.ts    From dev-manager-desktop with Apache License 2.0 6 votes vote down vote up
constructor(
    translate: TranslateService,
    private update: UpdateService,
    private modalService: NgbModal,
  ) {
    translate.setDefaultLang('en');
    update.getRecentRelease().then(info => {
      let curVer = new SemVer(packageInfo.version, true);
      const until = update.ignoreUntil;
      if (until && curVer.compare(until) < 0) {
        curVer = new SemVer(until, true);
      }
      const remoteVer = new SemVer(info.tag_name, true);
      if (remoteVer.compare(curVer) > 0) {
        return this.notifyUpdate(info, remoteVer);
      }
    });
  }
Example #3
Source File: app.component.ts    From dev-manager-desktop with Apache License 2.0 6 votes vote down vote up
private async notifyUpdate(info: Release, version: SemVer): Promise<void> {
    return MessageDialogComponent.open(this.modalService, {
      title: `Update ${version.version} is available`,
      message: UpdateDetailsComponent,
      negative: 'Next time',
      positive: 'More info',
      alternative: 'Ignore this version',
      messageExtras: {release: info}
    }).result.then((result: boolean | null) => {
      switch (result) {
        case true: {
          shell.openExternal(info.html_url);
          break;
        }
        case false: {
          break;
        }
        case null: {
          this.update.ignoreUntil = version;
          break;
        }
      }
    });
  }
Example #4
Source File: lib.ts    From xcodebuild with The Unlicense 6 votes vote down vote up
export async function getDestination(
  xcodeVersion: SemVer,
  platform?: Platform
): Promise<string[]> {
  switch (platform) {
    case 'iOS':
    case 'tvOS':
    case 'watchOS': {
      const id = (await destinations())[platform]
      return ['-destination', `id=${id}`]
    }
    case 'macOS':
      return ['-destination', 'platform=macOS']
    case 'mac-catalyst':
      return ['-destination', 'platform=macOS,variant=Mac Catalyst']
    case undefined:
      if (semver.gte(xcodeVersion, '13.0.0')) {
        //FIXME should parse output from xcodebuild -showdestinations
        //NOTE `-json` doesn’t work
        // eg. the Package.swift could only allow iOS, assuming macOS is going to work OFTEN
        // but not ALWAYS
        return ['-destination', 'platform=macOS']
      } else {
        return []
      }
    default:
      throw new Error(`Invalid platform: ${platform}`)
  }
}
Example #5
Source File: lib.ts    From xcodebuild with The Unlicense 6 votes vote down vote up
export function getAction(
  xcodeVersion: SemVer,
  platform?: Platform
): string | undefined {
  const action = core.getInput('action')
  if (
    platform == 'watchOS' &&
    actionIsTestable(action) &&
    semver.lt(xcodeVersion, '12.5.0')
  ) {
    core.notice('Setting `action=build` for Apple Watch / Xcode <12.5')
    return 'build'
  }

  return action ?? undefined
}
Example #6
Source File: lib.ts    From xcodebuild with The Unlicense 6 votes vote down vote up
async function destinations(): Promise<Destination> {
  const out = await exec('xcrun', [
    'simctl',
    'list',
    '--json',
    'devices',
    'available',
  ])
  const devices = parseJSON<Devices>(out).devices

  const rv: { [key: string]: { v: SemVer; id: string } } = {}
  for (const opaqueIdentifier in devices) {
    const device = (devices[opaqueIdentifier] ?? [])[0]
    if (!device) continue
    const [type, v] = parse(opaqueIdentifier)
    if (v && (!rv[type] || semver.lt(rv[type].v, v))) {
      rv[type] = { v, id: device.udid }
    }
  }

  return {
    tvOS: rv.tvOS?.id,
    watchOS: rv.watchOS?.id,
    iOS: rv.iOS?.id,
  }

  function parse(key: string): [DeviceType, SemVer?] {
    const [type, ...vv] = (key.split('.').pop() ?? '').split('-')
    const v = semver.coerce(vv.join('.'))
    return [type as DeviceType, v ?? undefined]
  }
}
Example #7
Source File: lib.ts    From xcodebuild with The Unlicense 6 votes vote down vote up
async function xcodes(): Promise<[string, SemVer][]> {
  const paths = (
    await exec('mdfind', ['kMDItemCFBundleIdentifier = com.apple.dt.Xcode'])
  ).split('\n')
  const rv: [string, SemVer][] = []
  for (const path of paths) {
    if (!path.trim()) continue
    const v = await mdls(path)
    if (v) {
      rv.push([path, v])
    }
  }
  return rv
}
Example #8
Source File: lib.ts    From xcodebuild with The Unlicense 6 votes vote down vote up
async function mdls(path: string): Promise<SemVer | undefined> {
  const v = await exec('mdls', ['-raw', '-name', 'kMDItemVersion', path])
  if (core.getInput('verbosity') == 'verbose') {
    // in verbose mode all commands and outputs are printed
    // and mdls in `raw` mode does not terminate its lines
    process.stdout.write('\n')
  }
  return semver.coerce(v) ?? undefined
}
Example #9
Source File: leanclient.ts    From vscode-lean4 with Apache License 2.0 6 votes vote down vote up
private extractVersion(v: string | undefined) : SemVer {
        if (!v) return new SemVer('0.0.0');
        const prefix = 'Lake version'
        if (v.startsWith(prefix)) v = v.slice(prefix.length).trim()
        const pos = v.indexOf('(')
        if (pos > 0) v = v.slice(0, pos).trim()
        try {
            return new SemVer(v)
        } catch {
            return new SemVer('0.0.0');
        }
    }
Example #10
Source File: gopInstallTools.ts    From vscode-goplus with Apache License 2.0 6 votes vote down vote up
export async function promptForUpdatingTool(toolName: string, newVersion?: SemVer) {
	const tool = getTool(toolName);
	const toolVersion = { ...tool, version: newVersion }; // ToolWithVersion

	// If user has declined to update, then don't prompt.
	if (containsTool(declinedUpdates, tool)) {
		return;
	}
	const goVersion = await getGoVersion();
	let updateMsg = `Your version of ${tool.name} appears to be out of date. Please update for an improved experience.`;
	const choices: string[] = ['Update'];
	if (toolName === `gopls`) {
		choices.push('Release Notes');
	}
	if (newVersion) {
		updateMsg = `A new version of ${tool.name} (v${newVersion}) is available. Please update for an improved experience.`;
	}
	const selected = await vscode.window.showInformationMessage(updateMsg, ...choices);
	switch (selected) {
		case 'Update':
			await installTools([toolVersion], goVersion);
			break;
		case 'Release Notes':
			vscode.commands.executeCommand(
				'vscode.open',
				vscode.Uri.parse('https://github.com/golang/go/issues/33030#issuecomment-510151934')
			);
			break;
		default:
			declinedUpdates.push(tool);
			break;
	}
}
Example #11
Source File: version.ts    From cuda-toolkit with MIT License 6 votes vote down vote up
// Helper for converting string to SemVer and verifying it exists in the links
export async function getVersion(
  versionString: string,
  method: Method
): Promise<SemVer> {
  const version = new SemVer(versionString)
  const links: AbstractLinks = await getLinks()
  let versions
  switch (method) {
    case 'local':
      versions = links.getAvailableLocalCudaVersions()
      break
    case 'network':
      switch (await getOs()) {
        case OSType.linux:
          // TODO adapt this to actual available network versions for linux
          versions = links.getAvailableLocalCudaVersions()
          break
        case OSType.windows:
          versions = (links as WindowsLinks).getAvailableNetworkCudaVersions()
          break
      }
  }
  core.debug(`Available versions: ${versions}`)
  if (versions.find(v => v.compare(version) === 0) !== undefined) {
    core.debug(`Version available: ${version}`)
    return version
  } else {
    core.debug(`Version not available error!`)
    throw new Error(`Version not available: ${version}`)
  }
}
Example #12
Source File: linux-links.test.ts    From cuda-toolkit with MIT License 6 votes vote down vote up
test.concurrent('Linux Cuda versions in descending order', async () => {
  const wLinks: AbstractLinks = LinuxLinks.Instance
  const versions = wLinks.getAvailableLocalCudaVersions()
  for (let i = 0; i < versions.length - 1; i++) {
    const versionA: SemVer = versions[i]
    const versionB: SemVer = versions[i + 1]
    expect(versionA.compare(versionB)).toBe(1) // A should be greater than B
  }
})
Example #13
Source File: windows-links.test.ts    From cuda-toolkit with MIT License 6 votes vote down vote up
test.concurrent(
  'Windows Cuda network versions in descending order',
  async () => {
    const wLinks = WindowsLinks.Instance
    const versions = wLinks.getAvailableNetworkCudaVersions()
    for (let i = 0; i < versions.length - 1; i++) {
      const versionA: SemVer = versions[i]
      const versionB: SemVer = versions[i + 1]
      expect(versionA.compare(versionB)).toBe(1) // A should be greater than B
    }
  }
)
Example #14
Source File: version.test.ts    From cuda-toolkit with MIT License 6 votes vote down vote up
test.concurrent.each<Method>(['local', 'network'])(
  'Successfully parse correct version for method %s',
  async method => {
    const versionString = '11.2.2'
    try {
      const version = await getVersion(versionString, method)
      expect(version).toBeInstanceOf(SemVer)
      expect(version.compare(new SemVer(versionString))).toBe(0)
    } catch (error) {
      // Other OS
    }
  }
)
Example #15
Source File: apt-installer.ts    From cuda-toolkit with MIT License 6 votes vote down vote up
export async function aptSetup(version: SemVer): Promise<void> {
  const osType = await getOs()
  if (osType !== OSType.linux) {
    throw new Error(
      `apt setup can only be run on linux runners! Current os type: ${osType}`
    )
  }
  core.debug(`Setup packages for ${version}`)
  const ubuntuVersion: string = await execReturnOutput('lsb_release', ['-sr'])
  const ubuntuVersionNoDot = ubuntuVersion.replace('.', '')
  const pinFilename = `cuda-ubuntu${ubuntuVersionNoDot}.pin`
  const arch = `x86_64`
  const pinUrl = `https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${ubuntuVersionNoDot}/${arch}/${pinFilename}`
  const repoUrl = `http://developer.download.nvidia.com/compute/cuda/repos/ubuntu${ubuntuVersionNoDot}/${arch}/`
  const keyRingVersion = `1.0-1`
  const keyRingUrl = `https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${ubuntuVersionNoDot}/${arch}/cuda-keyring_${keyRingVersion}_all.deb`
  const keyRingFilename = `cuda_keyring.deb`

  core.debug(`Pin filename: ${pinFilename}`)
  core.debug(`Pin url: ${pinUrl}`)
  core.debug(`Keyring url: ${keyRingUrl}`)

  core.debug(`Downloading keyring`)
  await exec(`wget ${keyRingUrl} -O ${keyRingFilename}`)
  await exec(`sudo dpkg -i ${keyRingFilename}`)

  core.debug('Adding CUDA Repository')
  await exec(`wget ${pinUrl}`)
  await exec(
    `sudo mv ${pinFilename} /etc/apt/preferences.d/cuda-repository-pin-600`
  )
  await exec(`sudo add-apt-repository "deb ${repoUrl} /"`)
  await exec(`sudo apt-get update`)
}
Example #16
Source File: apt-installer.ts    From cuda-toolkit with MIT License 6 votes vote down vote up
export async function aptInstall(
  version: SemVer,
  subPackages: string[]
): Promise<number> {
  const osType = await getOs()
  if (osType !== OSType.linux) {
    throw new Error(
      `apt install can only be run on linux runners! Current os type: ${osType}`
    )
  }
  if (subPackages.length === 0) {
    // Install everything
    const packageName = `cuda-${version.major}-${version.minor}`
    core.debug(`Install package: ${packageName}`)
    return await exec(`sudo apt-get -y install`, [packageName])
  } else {
    // Only install specified packages
    const versionedSubPackages = subPackages.map(
      subPackage => `cuda-${subPackage}-${version.major}-${version.minor}`
    )
    core.debug(`Only install subpackages: ${versionedSubPackages}`)
    return await exec(`sudo apt-get -y install`, versionedSubPackages)
  }
}
Example #17
Source File: links.ts    From cuda-toolkit with MIT License 5 votes vote down vote up
getAvailableLocalCudaVersions(): SemVer[] {
    return Array.from(this.cudaVersionToURL.keys()).map(s => new SemVer(s))
  }
Example #18
Source File: windows-links.ts    From cuda-toolkit with MIT License 5 votes vote down vote up
getNetworkURLFromCudaVersion(version: SemVer): URL {
    const urlString = this.cudaVersionToNetworkUrl.get(`${version}`)
    if (urlString === undefined) {
      throw new Error(`Invalid version: ${version}`)
    }
    return new URL(urlString)
  }
Example #19
Source File: AppUpdater.ts    From electron-differential-updater with MIT License 5 votes vote down vote up
function hasPrereleaseComponents(version: SemVer) {
  const versionPrereleaseComponent = getVersionPreleaseComponents(version);
  return (
    versionPrereleaseComponent != null && versionPrereleaseComponent.length > 0
  );
}
Example #20
Source File: AppUpdater.ts    From electron-differential-updater with MIT License 5 votes vote down vote up
/**
   * The current application version.
   */
  readonly currentVersion: SemVer;
Example #21
Source File: links.ts    From cuda-toolkit with MIT License 5 votes vote down vote up
getLocalURLFromCudaVersion(version: SemVer): URL {
    const urlString = this.cudaVersionToURL.get(`${version}`)
    if (urlString === undefined) {
      throw new Error(`Invalid version: ${version}`)
    }
    return new URL(urlString)
  }
Example #22
Source File: index.ts    From action with MIT License 5 votes vote down vote up
async function main (): Promise<void> {
  try {
    const changelogFile = core.getInput('changelog-file') || '.generated-go-semantic-release-changelog.md'
    let args = ['--version-file', '--changelog', changelogFile]
    if (core.getInput('github-token')) {
      args.push('--token')
      args.push(core.getInput('github-token'))
    }
    if (getBooleanInput('prerelease')) {
      args.push('--prerelease')
    }
    if (getBooleanInput('prepend')) {
      args.push('--prepend-changelog')
    }
    if (getBooleanInput('dry')) {
      args.push('--dry')
    }
    if (core.getInput('update-file')) {
      args.push('--update')
      args.push(core.getInput('update-file'))
    }
    if (getBooleanInput('ghr')) {
      args.push('--ghr')
    }
    if (getBooleanInput('allow-initial-development-versions')) {
      args.push('--allow-initial-development-versions')
    }
    if (getBooleanInput('force-bump-patch-version')) {
      args.push('--force-bump-patch-version')
    }
    if (core.getInput('changelog-generator-opt')) {
      const changelogOpts = core.getInput('changelog-generator-opt').split(',').filter(String)
      for (let idx = 0; idx < changelogOpts.length; idx++) {
        args.push('--changelog-generator-opt')
        args.push(changelogOpts[idx])
      }
    }
    if (core.getInput('hooks')) {
      args.push('--hooks')
      args.push(core.getInput('hooks'))
    }
    if (core.getInput('custom-arguments')) {
      args = args.concat(core.getInput('custom-arguments').split(' ').filter(String))
    }

    let binPath = core.getInput('bin')
    if (!binPath) binPath = await installer()

    try {
      core.info('running semantic-release...')
      await exec.exec(binPath, args)
    } catch (error) {
      if (/exit code 6\d/.test(error.message)) {
        return
      }
      core.setFailed(error.message)
      return
    }
    const generatedChangelog = (await fs.readFile(changelogFile)).toString('utf8')
    const versionFilename = (core.getInput('dry')) ? '.version-unreleased' : '.version'
    const version = (await fs.readFile(versionFilename)).toString('utf8')
    await fs.unlink(versionFilename)
    const parsedVersion = new SemVer(version)
    core.setOutput('changelog', generatedChangelog)
    core.debug(`setting version to ${parsedVersion.version}`)
    core.setOutput('version', parsedVersion.version)
    core.setOutput('version_major', `${parsedVersion.major}`)
    core.setOutput('version_minor', `${parsedVersion.minor}`)
    core.setOutput('version_patch', `${parsedVersion.patch}`)
    core.setOutput('version_prerelease', parsedVersion.prerelease.join('.'))
  } catch (error) {
    core.setFailed(error.message)
  }
}
Example #23
Source File: windows-links.ts    From cuda-toolkit with MIT License 5 votes vote down vote up
getAvailableNetworkCudaVersions(): SemVer[] {
    return Array.from(this.cudaVersionToNetworkUrl.keys()).map(
      s => new SemVer(s)
    )
  }
Example #24
Source File: update-path.ts    From cuda-toolkit with MIT License 5 votes vote down vote up
export async function updatePath(version: SemVer): Promise<string> {
  let cudaPath: string
  switch (await getOs()) {
    case OSType.linux:
      cudaPath = `/usr/local/cuda-${version.major}.${version.minor}`
      break
    case OSType.windows:
      cudaPath = `C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v${version.major}.${version.minor}`
  }
  core.debug(`Cuda path: ${cudaPath}`)
  // Export $CUDA_PATH
  core.exportVariable('CUDA_PATH', cudaPath)
  core.debug(`Cuda path vx_y: ${cudaPath}`)
  // Export $CUDA_PATH_VX_Y
  core.exportVariable(`CUDA_PATH_V${version.major}_${version.minor}`, cudaPath)
  core.exportVariable(
    'CUDA_PATH_VX_Y',
    `CUDA_PATH_V${version.major}_${version.minor}`
  )
  // Add $CUDA_PATH/bin to $PATH
  const binPath = path.join(cudaPath, 'bin')
  core.debug(`Adding to PATH: ${binPath}`)
  core.addPath(binPath)

  // Update LD_LIBRARY_PATH on linux, see: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#environment-setup
  if ((await getOs()) === OSType.linux) {
    // Get LD_LIBRARY_PATH
    const libPath = process.env.LD_LIBRARY_PATH
      ? process.env.LD_LIBRARY_PATH
      : ''
    // Get CUDA lib path
    const cudaLibPath = path.join(cudaPath, 'lib64')
    // Check if CUDA lib path is already in LD_LIBRARY_PATH
    if (!libPath.split(':').includes(cudaLibPath)) {
      // CUDA lib is not in LD_LIBRARY_PATH, so add it
      core.debug(`Adding to LD_LIBRARY_PATH: ${cudaLibPath}`)
      core.exportVariable(
        'LD_LIBRARY_PATH',
        cudaLibPath + path.delimiter + libPath
      )
    }
  }
  // Return cuda path
  return cudaPath
}
Example #25
Source File: installer.ts    From cuda-toolkit with MIT License 4 votes vote down vote up
export async function install(
  executablePath: string,
  version: SemVer,
  subPackagesArray: string[],
  linuxLocalArgsArray: string[]
): Promise<void> {
  // Install arguments, see: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#runfile-advanced
  // and https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html
  let installArgs: string[]

  // Command string that is executed
  let command: string

  // Subset of subpackages to install instead of everything, see: https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html#install-cuda-software
  const subPackages: string[] = subPackagesArray

  // Execution options which contain callback functions for stdout and stderr of install process
  const execOptions = {
    listeners: {
      stdout: (data: Buffer) => {
        core.debug(data.toString())
      },
      stderr: (data: Buffer) => {
        core.debug(`Error: ${data.toString()}`)
      }
    }
  }

  // Configure OS dependent run command and args
  switch (await getOs()) {
    case OSType.linux:
      // Root permission needed on linux
      command = `sudo ${executablePath}`
      // Install silently, and add additional arguments
      installArgs = ['--silent'].concat(linuxLocalArgsArray)
      break
    case OSType.windows:
      // Windows handles permissions automatically
      command = executablePath
      // Install silently
      installArgs = ['-s']
      // Add subpackages to command args (if any)
      installArgs = installArgs.concat(
        subPackages.map(subPackage => {
          // Display driver sub package name is not dependent on version
          if (subPackage === 'Display.Driver') {
            return subPackage
          }
          return `${subPackage}_${version.major}.${version.minor}`
        })
      )
      break
  }

  // Run installer
  try {
    core.debug(`Running install executable: ${executablePath}`)
    const exitCode = await exec(command, installArgs, execOptions)
    core.debug(`Installer exit code: ${exitCode}`)
  } catch (error) {
    core.debug(`Error during installation: ${error}`)
    throw error
  } finally {
    // Always upload installation log regardless of error
    if ((await getOs()) === OSType.linux) {
      const artifactClient = artifact.create()
      const artifactName = 'install-log'
      const files = ['/var/log/cuda-installer.log']
      const rootDirectory = '/var/log'
      const artifactOptions = {
        continueOnError: true
      }
      const uploadResult = await artifactClient.uploadArtifact(
        artifactName,
        files,
        rootDirectory,
        artifactOptions
      )
      core.debug(`Upload result: ${uploadResult}`)
    }
  }
}
Example #26
Source File: downloader.ts    From cuda-toolkit with MIT License 4 votes vote down vote up
// Download helper which returns the installer executable and caches it for next runs
export async function download(
  version: SemVer,
  method: Method
): Promise<string> {
  // First try to find tool with desired version in tool cache
  const toolName = 'cuda_installer'
  const osType = await getOs()
  const toolPath = tc.find(`${toolName}-${osType}`, `${version}`)
  // Path that contains the executable file
  let executablePath: string
  if (toolPath) {
    // Tool is already in cache
    core.debug(`Found in cache ${toolPath}`)
    executablePath = toolPath
  } else {
    core.debug(`Not found in cache, downloading...`)
    // Get download URL
    const links: AbstractLinks = await getLinks()
    let url: URL
    switch (method) {
      case 'local':
        url = links.getLocalURLFromCudaVersion(version)
        break
      case 'network':
        if (!(links instanceof WindowsLinks)) {
          core.debug(`Tried to get windows links but got linux links instance`)
          throw new Error(
            `Network mode is not supported by linux, shouldn't even get here`
          )
        }
        url = links.getNetworkURLFromCudaVersion(version)
    }
    // Get intsaller filename extension depending on OS
    let fileExtension: string
    switch (osType) {
      case OSType.windows:
        fileExtension = 'exe'
        break
      case OSType.linux:
        fileExtension = 'run'
        break
    }
    // Pathname for destination
    const destFileName = `${toolName}_${version}.${fileExtension}`
    // Download executable
    const path: string = await tc.downloadTool(url.toString(), destFileName)
    // Cache download
    const cachedPath = await tc.cacheFile(
      path,
      destFileName,
      `${toolName}-${osType}`,
      `${version}`
    )
    executablePath = cachedPath
  }
  // String with full executable path
  let fullExecutablePath: string
  // Get list of files in tool cache
  const filesInCache = await (
    await glob.create(`${executablePath}/**.*`)
  ).glob()
  core.debug(`Files in tool cache:`)
  for (const f of filesInCache) {
    core.debug(f)
  }
  if (filesInCache.length > 1) {
    throw new Error(`Got multiple file in tool cache: ${filesInCache.length}`)
  } else if (filesInCache.length === 0) {
    throw new Error(`Got no files in tool cahce`)
  } else {
    fullExecutablePath = filesInCache[0]
  }
  // Make file executable on linux
  if ((await getOs()) === OSType.linux) {
    // 0755 octal notation permission is: owner(r,w,x), group(r,w,x), other(r,x) where r=read, w=write, x=execute
    await fs.promises.chmod(fullExecutablePath, '0755')
  }
  // Return full executable path
  return fullExecutablePath
}
Example #27
Source File: lib.ts    From xcodebuild with The Unlicense 4 votes vote down vote up
export async function xcselect(xcode?: Range, swift?: Range): Promise<SemVer> {
  if (swift) {
    return selectSwift(swift)
  } else if (xcode) {
    return selectXcode(xcode)
  }

  const gotDotSwiftVersion = dotSwiftVersion()
  if (gotDotSwiftVersion) {
    core.info(`» \`.swift-version\` » ~> ${gotDotSwiftVersion}`)
    return selectSwift(gotDotSwiftVersion)
  } else {
    // figure out the GHA image default Xcode’s version

    const devdir = await exec('xcode-select', ['--print-path'])
    const xcodePath = path.dirname(path.dirname(devdir))
    const version = await mdls(xcodePath)
    if (version) {
      return version
    } else {
      // shouldn’t happen, but this action needs to know the Xcode version
      // or we cannot function, this way we are #continuously-resilient
      return selectXcode()
    }
  }

  async function selectXcode(range?: Range): Promise<SemVer> {
    const rv = (await xcodes())
      .filter(([, v]) => (range ? semver.satisfies(v, range) : true))
      .sort((a, b) => semver.compare(a[1], b[1]))
      .pop()

    if (!rv) throw new Error(`No Xcode ~> ${range}`)

    spawn('sudo', ['xcode-select', '--switch', rv[0]])

    return rv[1]
  }

  async function selectSwift(range: Range): Promise<SemVer> {
    const rv1 = await xcodes()
    const rv2 = await Promise.all(rv1.map(swiftVersion))
    const rv3 = rv2
      .filter(([, , sv]) => semver.satisfies(sv, range))
      .sort((a, b) => semver.compare(a[1], b[1]))
      .pop()

    if (!rv3) throw new Error(`No Xcode with Swift ~> ${range}`)

    core.info(`» Selected Swift ${rv3[2]}`)

    spawn('sudo', ['xcode-select', '--switch', rv3[0]])

    return rv3[1]

    async function swiftVersion([DEVELOPER_DIR, xcodeVersion]: [
      string,
      SemVer
    ]): Promise<[string, SemVer, SemVer]> {
      // This command emits 'swift-driver version: ...' to stderr.
      const stdout = await exec(
        'swift',
        ['--version'],
        { DEVELOPER_DIR },
        false
      )
      const matches = stdout.match(/Swift version (.+?)\s/m)
      if (!matches || !matches[1])
        throw new Error(
          `failed to extract Swift version from Xcode ${xcodeVersion}`
        )
      const version = semver.coerce(matches[1])
      if (!version)
        throw new Error(
          `failed to parse Swift version from Xcode ${xcodeVersion}`
        )
      return [DEVELOPER_DIR, xcodeVersion, version]
    }
  }

  function dotSwiftVersion(): Range | undefined {
    if (!fs.existsSync('.swift-version')) return undefined
    const version = fs.readFileSync('.swift-version').toString().trim()
    try {
      // A .swift-version of '5.0' indicates a SemVer Range of '>=5.0.0 <5.1.0'
      return new Range('~' + version)
    } catch (error) {
      core.warning(
        `Failed to parse Swift version from .swift-version: ${error}`
      )
    }
  }
}
Example #28
Source File: configErrors.spec.ts    From cli with Apache License 2.0 4 votes vote down vote up
describe('configErrors', () => {
  afterEach(() => {
    jest.resetAllMocks();
  });

  describe('IncompatibleConfigurationError', () => {
    describe('when the version is undefined', () => {
      fancyIt()(
        'should have a message saying that no version has been found',
        () => {
          expect(new IncompatibleConfigurationError(undefined).message).toBe(
            'No version found in config'
          );
        }
      );
    });

    describe('when the version is not a string nor undefined', () => {
      fancyIt()(
        'should have a message saying that the version of the found type and that it expected a string',
        () => {
          expect(new IncompatibleConfigurationError(42).message).toBe(
            'Version found in config is a number. Expected a string.'
          );
        }
      );
    });

    describe('when the version is a non-semver-parsable string', () => {
      beforeEach(() => {
        mockedCoerce.mockReturnValueOnce(null);
      });

      fancyIt()(
        'should have a message saying that the version is not parsable',
        () => {
          expect(new IncompatibleConfigurationError('potato').message).toBe(
            "Version found in config 'potato' is not parsable to a valid semantic version."
          );
          expect(mockedCoerce).toBeCalledWith('potato');
        }
      );
    });

    describe('when the version is greater than the supported version', () => {
      const mockedSemverInstance = new SemVer('1.0.0');
      beforeEach(() => {
        mockedCoerce.mockReturnValue(mockedSemverInstance);
        mockedGt.mockReturnValueOnce(true);
      });

      fancyIt()(
        'should have a message saying that the version is greater than the one accepted',
        () => {
          expect(new IncompatibleConfigurationError('potato').message).toBe(
            "Version found in config 'potato' is greater than the one accepted by this version of the CLI."
          );
          expect(mockedGt).toBeCalledWith(
            mockedSemverInstance,
            CurrentSchemaVersion
          );
        }
      );
    });

    describe('when the version is lesser than the supported version', () => {
      const mockedSemverInstance = new SemVer('1.0.0');
      beforeEach(() => {
        mockedCoerce.mockReturnValue(mockedSemverInstance);
        mockedGt.mockReturnValueOnce(false);
        mockedLt.mockReturnValueOnce(true);
      });

      fancyIt()(
        'should have a message saying that the version is lesser than the one accepted',
        () => {
          expect(new IncompatibleConfigurationError('potato').message).toBe(
            "Version found in config 'potato' is less than the one accepted by this version of the CLI."
          );
          expect(mockedLt).toBeCalledWith(
            mockedSemverInstance,
            CurrentSchemaVersion
          );
        }
      );
    });

    describe('when the coerced version is not null, nor greater or lesser than the supported version', () => {
      const mockedSemverInstance = new SemVer('1.0.0');
      beforeEach(() => {
        mockedCoerce.mockReturnValue(mockedSemverInstance);
        mockedGt.mockReturnValueOnce(false);
        mockedLt.mockReturnValueOnce(false);
      });

      fancyIt()(
        'should have a message asking the user to report the issue',
        () => {
          expect(new IncompatibleConfigurationError('potato').message).toBe(
            dedent`
            Unknown config version error:
              - configVersion: potato
              - compatibleVersion: versionThatTheCliWant
            Please report this issue to Coveo.`
          );
        }
      );
    });
  });
});