From 9e46b885b645361f8fa5665aabf802abac7bbb8d Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Sat, 27 Jun 2020 22:47:55 +0300 Subject: [PATCH] fix: let semrel core take care about repositoryUrl BREAKING CHANGE: 1) removed custom url builder 2) `enterprise` flag if enabled checks the repoUrl not to be 'github.com' closes #80 --- src/main/ts/config.ts | 57 +++++++++------------ src/main/ts/interface.ts | 2 +- src/test/ts/config.ts | 104 +++++++-------------------------------- src/test/ts/index.ts | 20 ++++---- 4 files changed, 52 insertions(+), 131 deletions(-) diff --git a/src/main/ts/config.ts b/src/main/ts/config.ts index b3b9674..62fa4b7 100644 --- a/src/main/ts/config.ts +++ b/src/main/ts/config.ts @@ -15,6 +15,7 @@ import { DEFAULT_ENTERPRISE, DEFAULT_PULL_TAGS_BRANCH } from './defaults' +import AggregateError from 'aggregate-error' export { DEFAULT_BRANCH, @@ -55,14 +56,15 @@ export const extractRepoToken = (repoUrl: string): string => { /** * @private */ -export const getRepoUrl = (pluginConfig: TAnyMap, context: TContext): string => { +export const getRepoUrl = (pluginConfig: TAnyMap, context: TContext, enterprise: boolean): string => { const { env, logger } = context const urlFromEnv = getRepoUrlFromEnv(env) const urlFromStepOpts = pluginConfig.repositoryUrl const urlFromOpts = context?.options?.repositoryUrl || '' const urlFromPackage = getUrlFromPackage() + const reassemble = !!urlFromStepOpts || !urlFromOpts - const url = urlFromStepOpts || urlFromOpts || urlFromEnv || urlFromPackage + let url = urlFromStepOpts || urlFromOpts || urlFromEnv || urlFromPackage if (process.env.DEBUG) { logger.log('getRepoUrl:') @@ -70,12 +72,19 @@ export const getRepoUrl = (pluginConfig: TAnyMap, context: TContext): string => logger.log('urlFromStepOpts=', urlFromStepOpts) logger.log('urlFromOpts=', urlFromOpts) logger.log('urlFromPackage', urlFromPackage) - logger.log('url=', url) } if (GITIO_REPO_PATTERN.test(url)) { const res: any = request('GET', urlFromOpts, { followRedirects: false, timeout: 5000 }) - return res.headers.location + url = res.headers.location + } + + if (reassemble) { + url = reassembleRepoUrl(url, context) + } + + if (enterprise && extractRepoDomain(url) === 'github.com') { + throw new AggregateError(['repo refers to `github.com` but enterprise url is expected']) } return url @@ -102,45 +111,25 @@ export const getToken = (env: TAnyMap, repoUrl: string) => env.GH_TOKEN || env.G /** * @private */ -export const getRepo = (pluginConfig: TAnyMap, context: TContext, enterprise?: boolean): string | undefined => { - const { env, logger } = context - const repoUrl = getRepoUrl(pluginConfig, context) - const repoName = extractRepoName(repoUrl) - const repoDomain = extractRepoDomain(repoUrl) - const token = getToken(env, repoUrl) - const url = `https://${token}@${repoDomain}/${repoName}.git` - - if (process.env.DEBUG) { - logger.log('getRepo:') - logger.log('repoUrl=', repoUrl) - logger.log('repoName=', repoName) - logger.log('repoDomain=', repoDomain) - logger.log('has token=', !!token) - logger.log('enterprise=', enterprise) - } - - if (repoDomain === 'github.com' && repoName) { - return url - } +export const reassembleRepoUrl = (redirectedUrl: string, context: TContext): string | undefined => { + const { env } = context + const repoName = extractRepoName(redirectedUrl) + const repoDomain = extractRepoDomain(redirectedUrl) + const token = getToken(env, redirectedUrl) - if (enterprise) { - return repoName - ? url - : repoUrl - } + return `https://${token}@${repoDomain}/${repoName}.git` } /** * @private */ export const resolveConfig = (pluginConfig: TAnyMap, context: TContext, path = PLUGIN_PATH, step?: string): IGhpagesPluginConfig => { - const { env, logger } = context + const { logger } = context const opts = resolveOptions(pluginConfig, context, path, step) const enterprise = Boolean(opts.enterprise || pluginConfig.enterprise || DEFAULT_ENTERPRISE) - const repo = getRepo(pluginConfig, context, enterprise) - const repoUrl = getRepoUrl(pluginConfig, context) - const token = getToken(env, repoUrl) + const repo = getRepoUrl(pluginConfig, context, enterprise) const pullTagsBranch = anyDefined(opts.pullTagsBranch, opts._branch, DEFAULT_PULL_TAGS_BRANCH) + const token = getToken(context.env, repo) if (process.env.DEBUG) { logger.log('resolveConfig args:') @@ -157,8 +146,8 @@ export const resolveConfig = (pluginConfig: TAnyMap, context: TContext, path = P msg: opts.msg || DEFAULT_MSG, branch: opts.branch || DEFAULT_BRANCH, enterprise, - token, repo, + token, pullTagsBranch } } diff --git a/src/main/ts/interface.ts b/src/main/ts/interface.ts index 886e9fd..447e60e 100644 --- a/src/main/ts/interface.ts +++ b/src/main/ts/interface.ts @@ -24,8 +24,8 @@ export interface IGhpagesPluginConfig { dst: string, branch: string, msg: string, + repo: string, token?: string, - repo?: string, enterprise?: boolean, pullTagsBranch?: string } diff --git a/src/test/ts/config.ts b/src/test/ts/config.ts index d91c949..ad5ae4e 100644 --- a/src/test/ts/config.ts +++ b/src/test/ts/config.ts @@ -11,11 +11,11 @@ import { extractRepoName, getUrlFromPackage, getRepoUrl, - getRepo, + // getRepo, extractRepoDomain } from '../../main/ts/config' -import { TAnyMap, TContext, TStringMap } from '../../main/ts/interface' +import { TAnyMap, TContext } from '../../main/ts/interface' describe('config', () => { const repositoryUrl = getUrlFromPackage() @@ -31,7 +31,6 @@ describe('config', () => { repositoryUrl, plugins: [] } - const repoName = extractRepoName(repositoryUrl) it('exposes defaults', () => { ([DEFAULT_BRANCH, @@ -168,7 +167,7 @@ describe('config', () => { msg: DEFAULT_MSG, src: DEFAULT_SRC, token, - repo: `https://${token}@github.com/${repoName}.git`, + repo: repositoryUrl, pullTagsBranch: DEFAULT_PULL_TAGS_BRANCH }) }) @@ -285,83 +284,9 @@ describe('config', () => { cases.forEach(([input, result]) => expect(extractRepoDomain(input)).toBe(result)) }) - it('#getRepo returns proper repo url with token', () => { - const cases = [ - { - pluginConfig: { - - }, - context: { - logger, - options: { - ...globalConfig - }, - cwd, - env: { - GH_TOKEN: 'foo' - } - }, - enterprise: true, - result: 'https://foo@github.com/qiwi/semantic-release-gh-pages-plugin.git' - }, - { - pluginConfig: {}, - context: { - logger, - options: { - ...globalConfig, - repositoryUrl: 'https://github.qiwi.com/qiwi/foo.git' - }, - cwd, - env: { - GH_TOKEN: 'foo' - } as TStringMap - }, - enterprise: true, - result: 'https://foo@github.qiwi.com/qiwi/foo.git' - }, - { - pluginConfig: {}, - context: { - logger, - options: { - ...globalConfig, - repositoryUrl: '' - }, - cwd, - env: { - REPO_URL: 'http://github.qiwi.com/qiwi/foo', - GH_TOKEN: 'foo' - } - }, - enterprise: true, - result: 'https://foo@github.qiwi.com/qiwi/foo.git' - }, - { - pluginConfig: {}, - context: { - logger, - options: { - ...globalConfig, - repositoryUrl: '' - }, - cwd, - env: { - REPO_URL: 'http://github.qiwi.com/qiwi/foo', - GH_TOKEN: 'foo' - } - }, - enterprise: false, - result: undefined - } - ] - - cases.forEach(({ pluginConfig, context, enterprise, result }) => expect(getRepo(pluginConfig, context, enterprise)).toBe(result)) - }) - describe('#getRepoUrl', () => { it('returns proper value', () => { - const cases: Array<{pluginConfig: TAnyMap, context: TContext, result: string}> = + const cases: Array<{pluginConfig: TAnyMap, context: TContext, enterprise?: boolean, result: string}> = [ { pluginConfig: {}, @@ -386,11 +311,12 @@ describe('config', () => { cwd, env: {} }, + enterprise: true, result: 'bar' }, { pluginConfig: { - repositoryUrl: 'baz' + repositoryUrl: 'https://baz.com/foo/bar' }, context: { logger, @@ -398,9 +324,12 @@ describe('config', () => { ...globalConfig }, cwd, - env: {} + env: { + GH_TOKEN: 'token' + } }, - result: 'baz' + enterprise: true, + result: 'https://token@baz.com/foo/bar.git' }, { pluginConfig: {}, @@ -424,10 +353,12 @@ describe('config', () => { }, cwd, env: { - REPO_URL: 'bat' + GITHUB_TOKEN: 'secret', + REPO_URL: 'https://qux.com/foo/bar' } }, - result: 'bat' + enterprise: true, + result: 'https://secret@qux.com/foo/bar.git' }, { pluginConfig: {}, @@ -447,10 +378,11 @@ describe('config', () => { cases.forEach(({ pluginConfig, context, - result + result, + enterprise }) => { - expect(getRepoUrl(pluginConfig, context)).toBe(result) + expect(getRepoUrl(pluginConfig, context, !!enterprise)).toBe(result) }) }) }) diff --git a/src/test/ts/index.ts b/src/test/ts/index.ts index a3076b3..4b5e5ec 100644 --- a/src/test/ts/index.ts +++ b/src/test/ts/index.ts @@ -65,7 +65,7 @@ describe('index', () => { describe('verifyConditions', () => { it('populates plugin context with resolved config data and returns void', async () => { const { verifyConditions } = require('../../main/ts') - const { getRepo } = require('../../main/ts/config') + const { getRepoUrl } = require('../../main/ts/config') const context = { logger, options: { @@ -83,7 +83,7 @@ describe('index', () => { dst: DEFAULT_DST, src: DEFAULT_SRC, enterprise: DEFAULT_ENTERPRISE, - repo: getRepo(pluginConfig, context), + repo: getRepoUrl(pluginConfig, context, DEFAULT_ENTERPRISE), token, pullTagsBranch: DEFAULT_PULL_TAGS_BRANCH }) @@ -121,22 +121,22 @@ describe('index', () => { jest.resetModules() }) - it('asserts repository.url', async () => { + it('asserts enterprise url', async () => { const AggregateError = require('aggregate-error') const { verifyConditions } = require('../../main/ts') const context = { logger, options: { ...globalConfig, - [step]: [{ path }], - repositoryUrl: null + [step]: [[path, { enterprise: true }]], + repositoryUrl: 'https://github.com/qiwi/foobar.git' }, cwd, env: { GITHUB_TOKEN: token } } await expect(verifyConditions(pluginConfig, context)) - .rejects.toEqual(new AggregateError(['package.json repository.url does not match github.com pattern'])) + .rejects.toEqual(new AggregateError(['repo refers to `github.com` but enterprise url is expected'])) }) }) }) @@ -174,7 +174,7 @@ describe('index', () => { it('performs commit to docs branch via gh-pages util', async () => { const { publish: ghpagesPublish } = require('gh-pages') const { publish } = require('../../main/ts') - const { getRepo, resolveConfig } = require('../../main/ts/config') + const { getRepoUrl, resolveConfig } = require('../../main/ts/config') const { OK } = require('../../main/ts/ghpages') const pluginConfig = { foo: 'bar', @@ -196,7 +196,7 @@ describe('index', () => { env: { GITHUB_TOKEN: token } } const expectedOpts = { - repo: getRepo(pluginConfig, context), + repo: getRepoUrl(pluginConfig, context, false), branch: 'doc-branch', message: 'docs updated v{{=it.nextRelease.gitTag}}', dest: 'root' @@ -251,7 +251,7 @@ describe('index', () => { it('throws rejection on gh-pages fail', async () => { const { publish } = require('../../main/ts') - const { getRepo } = require('../../main/ts/config') + const { getRepoUrl } = require('../../main/ts/config') const pluginConfig = { foo: 'bar', baz: 'qux' @@ -266,7 +266,7 @@ describe('index', () => { env: { GITHUB_TOKEN: token + 'foo' } } const expectedOpts = { - repo: getRepo(pluginConfig, context), + repo: getRepoUrl(pluginConfig, context, false), branch: DEFAULT_BRANCH, message: DEFAULT_MSG, dest: DEFAULT_DST