diff --git a/.pnp.data.json b/.pnp.data.json index 7718efb..14bbe12 100644 --- a/.pnp.data.json +++ b/.pnp.data.json @@ -5683,14 +5683,6 @@ "@yarnpkg/esbuild-plugin-pnp", "virtual:f1c9a564e99f5792681c6023bceeff828fb9573df69b82ab16b101986bbe1f7e1a71b69e892a761e77f6819c82097d69464a2a8cb08949a00ab8be0c66a539eb#npm:2.0.0" ], - [ - "colorette", - "npm:2.0.16" - ], - [ - "dayjs", - "npm:1.10.7" - ], [ "esbuild", "npm:0.13.15" @@ -5703,6 +5695,10 @@ "js-yaml", "npm:4.1.0" ], + [ + "kleur", + "npm:4.1.4" + ], [ "light-spinner", "npm:1.0.4" @@ -7947,19 +7943,6 @@ ], "linkType": "HARD" } - ], - [ - "npm:2.0.16", - { - "packageLocation": "./.yarn/cache/colorette-npm-2.0.16-7b996485d7-cd55596a3a.zip/node_modules/colorette/", - "packageDependencies": [ - [ - "colorette", - "npm:2.0.16" - ] - ], - "linkType": "HARD" - } ] ] ], @@ -8543,24 +8526,6 @@ ] ] ], - [ - "dayjs", - [ - [ - "npm:1.10.7", - { - "packageLocation": "./.yarn/cache/dayjs-npm-1.10.7-34318a8e39-a0a4ca95ab.zip/node_modules/dayjs/", - "packageDependencies": [ - [ - "dayjs", - "npm:1.10.7" - ] - ], - "linkType": "HARD" - } - ] - ] - ], [ "debug", [ @@ -14449,6 +14414,24 @@ ] ] ], + [ + "kleur", + [ + [ + "npm:4.1.4", + { + "packageLocation": "./.yarn/cache/kleur-npm-4.1.4-7a73ff57c6-7f6db36e37.zip/node_modules/kleur/", + "packageDependencies": [ + [ + "kleur", + "npm:4.1.4" + ] + ], + "linkType": "HARD" + } + ] + ] + ], [ "language-subtag-registry", [ diff --git a/.yarn/cache/colorette-npm-2.0.16-7b996485d7-cd55596a3a.zip b/.yarn/cache/colorette-npm-2.0.16-7b996485d7-cd55596a3a.zip deleted file mode 100644 index 0d086dd..0000000 Binary files a/.yarn/cache/colorette-npm-2.0.16-7b996485d7-cd55596a3a.zip and /dev/null differ diff --git a/.yarn/cache/dayjs-npm-1.10.7-34318a8e39-a0a4ca95ab.zip b/.yarn/cache/dayjs-npm-1.10.7-34318a8e39-a0a4ca95ab.zip deleted file mode 100644 index f84b02f..0000000 Binary files a/.yarn/cache/dayjs-npm-1.10.7-34318a8e39-a0a4ca95ab.zip and /dev/null differ diff --git a/.yarn/cache/kleur-npm-4.1.4-7a73ff57c6-7f6db36e37.zip b/.yarn/cache/kleur-npm-4.1.4-7a73ff57c6-7f6db36e37.zip new file mode 100644 index 0000000..18f47b1 Binary files /dev/null and b/.yarn/cache/kleur-npm-4.1.4-7a73ff57c6-7f6db36e37.zip differ diff --git a/packages/ado-auth/package.json b/packages/ado-auth/package.json index a37a21f..e303f63 100644 --- a/packages/ado-auth/package.json +++ b/packages/ado-auth/package.json @@ -1,6 +1,6 @@ { "name": "ado-auth", - "version": "0.2.9", + "version": "0.2.11", "displayName": "ADO Authenticator", "license": "MIT", "main": "./bin/src/cli.js", @@ -20,7 +20,7 @@ "compile": "node ./scripts/build.mjs --minify", "typegen": "tsc", "build": "yarn compile && yarn typegen", - "prepublish": "yarn build && yarn typegen" + "prepublish": "yarn build" }, "repository": { "type": "git", @@ -28,9 +28,8 @@ }, "bin": "./bin/src/cli.js", "dependencies": { - "colorette": "2.0.16", - "dayjs": "1.10.7", "js-yaml": "4.1.0", + "kleur": "^4.1.4", "light-spinner": "1.0.4", "opener": "1.5.2", "sade": "1.7.4" diff --git a/packages/ado-auth/src/api-stuff/server.ts b/packages/ado-auth/src/api-stuff/server.ts index c0cf14c..14d3fe2 100644 --- a/packages/ado-auth/src/api-stuff/server.ts +++ b/packages/ado-auth/src/api-stuff/server.ts @@ -1,5 +1,5 @@ -import { bold, green } from 'colorette' import http, { Server } from 'http' +import { bold, green } from 'kleur/colors' import { SERVER_TIMEOUT } from '../lib/constants' import { CliOptions, Token } from '../lib/types' import { logger } from '../logger/logger' diff --git a/packages/ado-auth/src/cli.ts b/packages/ado-auth/src/cli.ts index 96c23a3..c42a35b 100644 --- a/packages/ado-auth/src/cli.ts +++ b/packages/ado-auth/src/cli.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -import { bold, greenBright } from 'colorette' +import { bold, red } from 'kleur/colors' import sade from 'sade' import { version } from '../package.json' import { CLIENT_ID, DEFAULT_HOST, SERVER_PORT } from './lib/constants' @@ -34,20 +34,20 @@ cli.action(async (config: CliOptions) => { if (!config.clientId) { config.clientId = CLIENT_ID } else { - logger.debug('Using client id - ', greenBright(bold(config.clientId))) + logger.debug('Using client id - ', red(bold(config.clientId))) } if (config.host !== DEFAULT_HOST) { logger.debug( 'Using cusotm host for authentication - ', - greenBright(bold(config.host)) + red(bold(config.host)) ) } if (config.port !== SERVER_PORT) { logger.debug( 'Using custom port for auth callback - ', - greenBright(bold(config.port)) + red(bold(`${config.port}`)) ) } diff --git a/packages/ado-auth/src/file-stuff/prepare.ts b/packages/ado-auth/src/file-stuff/prepare.ts index 5cbcb2c..acbc61d 100644 --- a/packages/ado-auth/src/file-stuff/prepare.ts +++ b/packages/ado-auth/src/file-stuff/prepare.ts @@ -1,7 +1,6 @@ -import dayjs from 'dayjs' import fs from 'fs' -import { PrepareReturn, PrepareTypes } from './prepare.types' import { TokenStore } from '../lib/types' +import { PrepareReturn, PrepareTypes } from './prepare.types' export function prepare(rcPath: string): PrepareReturn { if (fs.existsSync(rcPath)) { @@ -9,8 +8,11 @@ export function prepare(rcPath: string): PrepareReturn { const file = fs.readFileSync(rcPath, 'utf-8') try { const data: TokenStore = JSON.parse(file) - if (!dayjs(data.expires_on).isAfter(dayjs().subtract(1, 'minute'))) { - // expires in less than 1 minute + const isGoingToExpireInFiveMinutes = + new Date(data.expires_on) < new Date(Date.now() - 5 * 60 * 1000) + + if (isGoingToExpireInFiveMinutes) { + // expires in less than 5 minutes return { type: PrepareTypes.refetch, data, diff --git a/packages/ado-auth/src/lib/constants.ts b/packages/ado-auth/src/lib/constants.ts index 55f0c06..4f9188d 100644 --- a/packages/ado-auth/src/lib/constants.ts +++ b/packages/ado-auth/src/lib/constants.ts @@ -1,4 +1,4 @@ -import { yellow, bold } from 'colorette' +import { bold, yellow } from 'kleur/colors' export const SERVER_TIMEOUT = 60000 export const SERVER_PORT = 35287 diff --git a/packages/ado-auth/src/lib/operate.ts b/packages/ado-auth/src/lib/operate.ts index bcda45a..5cc9745 100644 --- a/packages/ado-auth/src/lib/operate.ts +++ b/packages/ado-auth/src/lib/operate.ts @@ -1,4 +1,4 @@ -import { bold, green, magenta, yellow } from 'colorette' +import { bold, green, magenta } from 'kleur/colors' import os from 'os' import path from 'path' import { auth } from '../api-stuff/auth' @@ -37,13 +37,13 @@ export async function operate(config: CliOptions) { let token: Token | undefined = undefined if (report.type === PrepareTypes.fetch) { - logger.debug(bold(magenta('Trying to get auth token'))) + logger.debug(magenta(bold('Trying to get auth token'))) token = await auth(rcPath, config) } else if (report.type === PrepareTypes.refetch) { - logger.debug(bold(magenta('Trying to refetch auth token'))) + logger.debug(magenta(bold('Trying to refetch auth token'))) token = await refetch(report.data, rcPath, config) } else if (report.type === PrepareTypes.noop) { - logger.debug('✅ ', bold(green('Valid token exists!'))) + logger.debug('✅ ', green(bold('Valid token exists!'))) token = report.data } diff --git a/packages/ado-auth/src/lib/readConfig.ts b/packages/ado-auth/src/lib/readConfig.ts index cbd09f9..bb781ce 100644 --- a/packages/ado-auth/src/lib/readConfig.ts +++ b/packages/ado-auth/src/lib/readConfig.ts @@ -1,9 +1,19 @@ -import { execSync } from 'child_process' -import { blue, bold, red } from 'colorette' +import { execSync, ExecSyncOptionsWithStringEncoding } from 'child_process' +import { blue, red } from 'kleur/colors' import { logger } from '../logger/logger' import { npmString, yarnString } from './constants' -const defaultRegex = /^(https?)?:?\/\/registry\.(yarnpkg|npmjs)\.(com|org).*/i +const defaultRegistryRegex = + /^(https?)?:?\/\/registry\.(yarnpkg|npmjs)\.(com|org).*/i + +const adoRegistryRegexes = [ + /^\/\/pkgs\.dev\.azure\.com/i, + /^\/\/(.*?).pkgs\.visualstudio\.com/i, +] + +function isAdoRegistry(registry: string) { + return adoRegistryRegexes.filter((ex) => ex.test(registry)).length > 0 +} const commands = { npm: 'npm config get registry', @@ -13,19 +23,68 @@ const commands = { type Tool = keyof typeof commands +const execParams: ExecSyncOptionsWithStringEncoding = { + encoding: 'utf8', + cwd: process.cwd(), +} + +function replaceHttps(input: string = '') { + return input.replace(/^https?:/, '') +} + +function getScopeRegistries(tool: Tool) { + try { + if (tool === 'npm' || tool === 'yarn') { + const config = JSON.parse(execSync(`npm config list --json`, execParams)) + + const registries: string[] = [] + + for (const entry in config) { + if (/@(.*?):registry/.test(entry)) { + registries.push(replaceHttps(config[entry])) + } + } + + return registries + } else if (tool === 'yarn2') { + const registries: string[] = [] + + const npmScopes = JSON.parse( + execSync('yarn config get npmScopes --json', execParams) + ) + + for (const entry of npmScopes) { + registries.push(replaceHttps(entry.npmRegistryServer)) + } + + return registries + } + } catch (error) { + logger.debug('No scoped registries found') + } +} + const toolNames: Record = { npm: npmString, yarn: yarnString, yarn2: yarnString, } +function isValidRegistryEntry(registry: string) { + return ( + !/undefined/i.test(registry) && + isAdoRegistry(registry) && + !defaultRegistryRegex.test(registry) + ) +} + function getRegistry(tool: Exclude) { - let registry = '' + let registries: string[] = [] let toolToUse: Tool = tool if (tool === 'yarn') { - const version = execSync('yarn -v', { encoding: 'utf8' })?.trim() + const version = execSync('yarn -v', execParams)?.trim() const match = version.match(/(\d+)\.*/i) if (Number(match?.[1]) >= 2) { @@ -34,15 +93,18 @@ function getRegistry(tool: Exclude) { } try { - registry = execSync(commands[toolToUse], { - encoding: 'utf8', - cwd: process.cwd(), - }) - ?.trim() - .replace(/^https?:/, '') // remove https - - if (defaultRegex.test(registry) || /undefined/i.test(registry)) { - registry = '' + const registry = execSync(commands[toolToUse], execParams)?.trim() + + if (isValidRegistryEntry(registry)) { + registries.push(replaceHttps(registry)) + } + + logger.debug('Trying to add scoped registries') + + for (const entry of getScopeRegistries(toolToUse) || []) { + if (isValidRegistryEntry(entry)) { + registries.push(entry) + } } } catch (error) { logger.debug( @@ -51,33 +113,35 @@ function getRegistry(tool: Exclude) { ) } - if (!registry) { - logger.debug(`No custom ${toolNames[toolToUse]} registry found.`) - } else { + if (!registries.length) { logger.debug( - `${toolNames[toolToUse]} config contains this registry -> `, - blue(registry) + `No custom ${toolNames[toolToUse]} Azure DevOps registry found.` ) + } else { + logger.debug(`${toolNames[toolToUse]} config contains these registries -> `) + for (const registry of registries) { + logger.debug(`\t ${blue(registry)}`) + } } - return registry + return registries } export function readConfig() { - let npmRegistry: string | undefined + let npmRegistries: string[] = [] try { - npmRegistry = getRegistry('npm') + npmRegistries.push(...getRegistry('npm')) } catch (error) { if (error instanceof Error) { logger.debug('running npm failed - ', red(error.message)) } } - let yarnRegistry: string | undefined + let yarnRegistries: string[] = [] try { - yarnRegistry = getRegistry('yarn') + yarnRegistries.push(...getRegistry('yarn')) } catch (error) { if (error instanceof Error) { logger.debug('running yarn failed - ', red(error.message)) @@ -86,8 +150,8 @@ export function readConfig() { return new Set( [ - ...getRegistryEntries(npmRegistry), - ...getRegistryEntries(yarnRegistry), + ...npmRegistries.flatMap((reg) => getRegistryEntries(reg)), + ...yarnRegistries.flatMap((reg) => getRegistryEntries(reg)), ].filter(Boolean) ) } diff --git a/packages/ado-auth/src/lib/spinner.ts b/packages/ado-auth/src/lib/spinner.ts index 82a2442..4aea983 100644 --- a/packages/ado-auth/src/lib/spinner.ts +++ b/packages/ado-auth/src/lib/spinner.ts @@ -1,5 +1,5 @@ +import { dim } from 'kleur/colors' import Spin from 'light-spinner' -import { dim } from 'colorette' import { IOption } from 'light-spinner/dist/interface' export type PrefixedSpinnerOptions = IOption & { diff --git a/packages/ado-auth/src/lib/writeAdoRc.ts b/packages/ado-auth/src/lib/writeAdoRc.ts index 2e61075..c96b8bb 100644 --- a/packages/ado-auth/src/lib/writeAdoRc.ts +++ b/packages/ado-auth/src/lib/writeAdoRc.ts @@ -1,16 +1,25 @@ -import dayjs from 'dayjs' import fs from 'fs' import { Token } from './types' export function writeAdoRc(rcPath: string, response: Token) { + const expires_in_seconds = Number(response.expires_in) + + if (isNaN(expires_in_seconds)) { + throw Error( + 'Auth token has invalid expires_in property. Expected a number.' + ) + } + + const expires_on = new Date( + Date.now() + expires_in_seconds * 1000 + ).toISOString() + fs.writeFileSync( rcPath, JSON.stringify( { ...response, - expires_on: dayjs() - .add(Number(response.expires_in), 'seconds') - .toISOString(), + expires_on, }, null, ' ' diff --git a/packages/ado-auth/src/logger/logger.ts b/packages/ado-auth/src/logger/logger.ts index d12e9a5..553289c 100644 --- a/packages/ado-auth/src/logger/logger.ts +++ b/packages/ado-auth/src/logger/logger.ts @@ -1,4 +1,4 @@ -import { dim } from 'colorette' +import { dim } from 'kleur/colors' import Spin from 'light-spinner' import { PrefixedSpinner, PrefixedSpinnerOptions } from '../lib/spinner' @@ -43,14 +43,14 @@ class Logger { succeed: (text?: string) => { if (this.debugEnabled) { - this.debug(`✅ ${text || this._spinner?.text}`) + this.debug(`\n✅ ${text || this._spinner?.text}`) this._spinner?.stop() } }, fail: (text?: string) => { if (this.debugEnabled) { - this.debug(`❌ ${text || this._spinner?.text}`) + this.debug(`\n❌ ${text || this._spinner?.text}`) this._spinner?.stop() } }, diff --git a/packages/ado-auth/src/write-rc/npmrc.ts b/packages/ado-auth/src/write-rc/npmrc.ts index fce6621..220016a 100644 --- a/packages/ado-auth/src/write-rc/npmrc.ts +++ b/packages/ado-auth/src/write-rc/npmrc.ts @@ -1,5 +1,5 @@ -import { blue, bold, green, cyan } from 'colorette' import fs from 'fs' +import { blue, bold, cyan, green } from 'kleur/colors' import os from 'os' import path from 'path' import { AUTH_DELIMITER } from '../lib/constants' @@ -15,7 +15,7 @@ type WriteNpmrcParams = { export function writeNpmrc({ npmrcPath, registries, token }: WriteNpmrcParams) { let newNpmRc = '' - logger.debug(`${bold(registries.size)} registries to be updated`) + logger.debug(`${bold(`${registries.size}`)} registries to be updated`) if (fs.existsSync(npmrcPath)) { logger.debug(`found ${cyan(bold('.npmrc'))} in home directory`) @@ -56,7 +56,7 @@ export function writeNpmrc({ npmrcPath, registries, token }: WriteNpmrcParams) { } if (newNpmRc) { - logger.debug('✏️ ', green(`Writing ${cyan(bold('~/.npmrc'))}`)) + logger.debug('✏️ ', green(`Writing`), cyan(bold('~/.npmrc'))) fs.writeFileSync(path.resolve(os.homedir(), '.npmrc'), newNpmRc) } } diff --git a/packages/ado-auth/src/write-rc/yarn2rc.ts b/packages/ado-auth/src/write-rc/yarn2rc.ts index ac063f1..850ca8e 100644 --- a/packages/ado-auth/src/write-rc/yarn2rc.ts +++ b/packages/ado-auth/src/write-rc/yarn2rc.ts @@ -1,6 +1,6 @@ -import { blue, bold, cyan, green } from 'colorette' import fs from 'fs' import yaml from 'js-yaml' +import { blue, bold, cyan, green } from 'kleur/colors' import os from 'os' import path from 'path' import { Token, YarnRcRegistryPart } from '../lib/types' @@ -37,7 +37,7 @@ export function writeYarn2rc({ registries, token, yarnrcPath }: Yarn2RcParams) { } } } else { - logger.debug(`No ${bold(cyan('.yarnrc.yml'))} found in home directory`) + logger.debug(`No ${cyan(bold('.yarnrc.yml'))} found in home directory`) } const yarnRcDump = registries.size @@ -69,7 +69,7 @@ export function writeYarn2rc({ registries, token, yarnrcPath }: Yarn2RcParams) { } as YarnRcRegistryPart) if (contents) { - logger.debug('✏️ ', green(`Writing ${bold(cyan('~/.yarnrc.yml'))}`)) + logger.debug('✏️ ', green(`Writing`), cyan(bold('~/.yarnrc.yml'))) fs.writeFileSync(path.resolve(os.homedir(), '.yarnrc.yml'), contents) } } diff --git a/yarn.lock b/yarn.lock index 6ae5bb2..221f9eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1768,11 +1768,10 @@ __metadata: "@types/opener": 1.4.0 "@types/sade": 1.7.3 "@yarnpkg/esbuild-plugin-pnp": 2.0.0 - colorette: 2.0.16 - dayjs: 1.10.7 esbuild: 0.13.15 esbuild-runner: 2.2.1 js-yaml: 4.1.0 + kleur: ^4.1.4 light-spinner: 1.0.4 opener: 1.5.2 sade: 1.7.4 @@ -2567,13 +2566,6 @@ __metadata: languageName: node linkType: hard -"colorette@npm:2.0.16": - version: 2.0.16 - resolution: "colorette@npm:2.0.16" - checksum: cd55596a3a2d1071c1a28eee7fd8a5387593ff1bd10a3e8d0a6221499311fe34a9f2b9272d77c391e0e003dcdc8934fb2f8d106e7ef1f7516f8060c901d41a27 - languageName: node - linkType: hard - "colorette@npm:^1.2.2": version: 1.4.0 resolution: "colorette@npm:1.4.0" @@ -2788,13 +2780,6 @@ __metadata: languageName: node linkType: hard -"dayjs@npm:1.10.7": - version: 1.10.7 - resolution: "dayjs@npm:1.10.7" - checksum: a0a4ca95abaa03d0702161dc2c35d16121188e342f5052b9c61cdf784dab68af766f477c04f87f71c6af666fd4d13db9b9853b87265850d6093b7b04e1bb1cd7 - languageName: node - linkType: hard - "debug@npm:2, debug@npm:^2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" @@ -4925,6 +4910,13 @@ __metadata: languageName: node linkType: hard +"kleur@npm:^4.1.4": + version: 4.1.4 + resolution: "kleur@npm:4.1.4" + checksum: 7f6db36e378045dec14acd3cbf0b1e59130c09e984ee8b8ce56dd2d2257cfff90389c1e8f8b19bd09dd5d241080566a814b4ccd99fdcef91f59ef93ec33c8a44 + languageName: node + linkType: hard + "language-subtag-registry@npm:~0.3.2": version: 0.3.21 resolution: "language-subtag-registry@npm:0.3.21"