diff --git a/README.md b/README.md index 3fc32a2..1794433 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,9 @@ or even shorter if default settings are used: | `src` | Documentation directory | `docs`

**NOTE** don't forget to run docs builder (`yarn docs`, `yarn typedoc`, etc) as a part of your build step or any other way| | `dst` | Destination directory | `.` (root) | | `branch` | Docs branch to push | `gh-pages` | +| `branches` | Optional list of src-to-target branches association. If defined it suppresses `branch` option. For example, `[['master', 'gh-pages'], ['beta', beta-docs]]` | undefined | | `repositoryUrl` | Repository url | inherited from .git | | `enterprise` | Disables host assertion for GitHub Enterprise domains | false | | `pullTagsBranch`| Target branch for tags fetching hook. If '' empty string, skips this action | `globalConfig.branch` \|\| `master` | -| `dotfiles`| gh-pages [dotfiles](https://github.com/tschaub/gh-pages#optionsdotfiles) option | `false` | -| `add`| gh-pages [add](https://github.com/tschaub/gh-pages#optionsadd) option | `false` | +| `dotfiles` | gh-pages [dotfiles](https://github.com/tschaub/gh-pages#optionsdotfiles) option | `false` | +| `add` | gh-pages [add](https://github.com/tschaub/gh-pages#optionsadd) option | `false` | diff --git a/src/main/ts/config.ts b/src/main/ts/config.ts index ee19284..ffb94aa 100644 --- a/src/main/ts/config.ts +++ b/src/main/ts/config.ts @@ -126,28 +126,42 @@ export const reassembleRepoUrl = (redirectedUrl: string, context: TContext): str */ export const resolveConfig = async (pluginConfig: TAnyMap, context: TContext, path = PLUGIN_PATH, step?: string): Promise => { const opts = resolveOptions(pluginConfig, context, path, step) + const { + branches, + branch = DEFAULT_BRANCH, + msg = DEFAULT_MSG, + src = DEFAULT_SRC, + dst = DEFAULT_DST, + add, + dotfiles + } = opts const enterprise = Boolean(opts.enterprise || pluginConfig.enterprise || DEFAULT_ENTERPRISE) const repo = await getRepoUrl(pluginConfig, context, enterprise) - const pullTagsBranch = anyDefined(opts.pullTagsBranch, opts._branch, DEFAULT_PULL_TAGS_BRANCH) + const ciBranch = context?.branch?.name as string + const docsBranch = branches ? branches.find(([from]: string[]) => from === ciBranch)?.[1] : branch + const pullTagsBranch = anyDefined(opts.pullTagsBranch, ciBranch, opts._branch, DEFAULT_PULL_TAGS_BRANCH) const token = getToken(context.env, repo) debug('resolveConfig args:') debug('pluginConfig= %j', pluginConfig) debug('path= %s', path) debug('step= %s', step) + debug('ciBranch= %s', ciBranch) + debug('docsBranch= %s', docsBranch) debug('pullTagsBranch= %s', pullTagsBranch) return { - src: opts.src || DEFAULT_SRC, - dst: opts.dst || DEFAULT_DST, - msg: opts.msg || DEFAULT_MSG, - branch: opts.branch || DEFAULT_BRANCH, + src, + dst, + msg, + ciBranch, + pullTagsBranch, + docsBranch, enterprise, repo, token, - pullTagsBranch, - add: opts.add, - dotfiles: opts.dotfiles, + add, + dotfiles, } } @@ -156,7 +170,7 @@ export const resolveConfig = async (pluginConfig: TAnyMap, context: TContext, pa */ export const resolveOptions = (pluginConfig: TAnyMap, context: TContext, path = PLUGIN_PATH, step?: string): TAnyMap => { const { options } = context - const base = omit(pluginConfig, 'branch') + const base = omit(pluginConfig, 'branch', 'branches') const extra = step && options[step] && castArray(options[step]) .map(config => { if (Array.isArray(config)) { diff --git a/src/main/ts/ghpages.ts b/src/main/ts/ghpages.ts index f04b78c..bc97ac7 100644 --- a/src/main/ts/ghpages.ts +++ b/src/main/ts/ghpages.ts @@ -43,7 +43,7 @@ export const pushPages = (opts: IPushOpts) => new Promise((resolve, reject) => { const { src, logger } = opts const ghpagesOpts: PublishOptions = { repo: opts.repo, - branch: opts.branch, + branch: opts.docsBranch, dest: opts.dst, message: opts.message, add: opts.add, diff --git a/src/main/ts/index.ts b/src/main/ts/index.ts index 5e8a54e..36e6470 100644 --- a/src/main/ts/index.ts +++ b/src/main/ts/index.ts @@ -17,19 +17,26 @@ let _config: any export const verifyConditions = async (pluginConfig: any, context: TContext) => { const { logger } = context const config = await resolveConfig(pluginConfig, context, undefined, 'publish') + const { token, repo, src, ciBranch, docsBranch } = config + + if (!docsBranch) { + logger.log(`gh-pages [skipped]: 'docsBranch' is empty for ${ciBranch}`) + return + } logger.log('verify gh-pages config') - if (!config.token) { + + if (!token) { throw new AggregateError(['env.GH_TOKEN is required by gh-pages plugin']) } - if (!config.repo) { + if (!repo) { throw new AggregateError(['package.json repository.url does not match github.com pattern']) } - if (!fs.existsSync(config.src) || !fs.lstatSync(config.src).isDirectory()) { - logger.error('Resolved docs src path=', path.resolve(config.src)) + if (!fs.existsSync(src) || !fs.lstatSync(src).isDirectory()) { + logger.error('Resolved docs src path=', path.resolve(src)) throw new AggregateError(['docs source directory does not exist']) } @@ -41,7 +48,8 @@ export const verifyConditions = async (pluginConfig: any, context: TContext) => export const publish = async (pluginConfig: any, context: TContext) => { const config = await resolveConfig(pluginConfig, context, undefined, 'publish') const { logger, env, cwd } = context - const message = render(config.msg, context, logger) + const { msg, docsBranch, ciBranch } = config + const message = render(msg, context, logger) const pushOpts: IPushOpts = { ...config, message, @@ -50,6 +58,11 @@ export const publish = async (pluginConfig: any, context: TContext) => { cwd } + if (!docsBranch) { + logger.log(`gh-pages [skipped]: 'docsBranch' is empty for ${ciBranch}`) + return + } + if (!isEqual(_config, config)) { await verifyConditions(pluginConfig, context) } diff --git a/src/main/ts/interface.ts b/src/main/ts/interface.ts index 78447b9..f87bedc 100644 --- a/src/main/ts/interface.ts +++ b/src/main/ts/interface.ts @@ -1,6 +1,6 @@ /** @module semantic-release-gh-pages-plugin */ -import { Context } from 'semantic-release' +import { BranchSpec, Context } from 'semantic-release' export interface ILogger { @@ -18,6 +18,7 @@ export type TStringMap = { export type TContext = Context & { env: TStringMap, + branch?: Exclude cwd: string, options: TAnyMap & { publish?: Array, @@ -28,12 +29,13 @@ export type TContext = Context & { export interface IGhpagesPluginConfig { src: string, dst: string, - branch: string, + ciBranch: string, + docsBranch: string, + pullTagsBranch?: string msg: string, repo: string, token?: string, enterprise?: boolean, - pullTagsBranch?: string dotfiles?: boolean add?: boolean } diff --git a/src/test/ts/config.ts b/src/test/ts/config.ts index 5089a25..6273b34 100644 --- a/src/test/ts/config.ts +++ b/src/test/ts/config.ts @@ -12,7 +12,8 @@ import { getUrlFromPackage, PLUGIN_PATH, resolveConfig, - resolveOptions} from '../../main/ts/config' + resolveOptions, +} from '../../main/ts/config' import { TAnyMap, TContext } from '../../main/ts/interface' describe('config', () => { @@ -127,7 +128,7 @@ describe('config', () => { src: 'docsdocs', dst: 'root', enterprise: true, - branch: DEFAULT_BRANCH, + docsBranch: DEFAULT_BRANCH, msg: 'doc update', token, repo: `https://${token}@enterprise.com/org/repo.git`, @@ -135,6 +136,53 @@ describe('config', () => { }) }) + it('overrides `docBranch` with `branches` value if defined', async () => { + const step = 'publish' + const path = PLUGIN_PATH + const token = 'token' + const pluginConfig = { + foo: 'bar', + baz: 'qux', + msg: 'doc update', + branch: 'master', // NOTE will be omitted, + branches: ['master', 'beta'], // NOTE will be omitted, + repositoryUrl: 'https://enterprise.com/org/repo.git' + } + const extra = { + enterprise: true, + src: 'docsdocs', + dst: 'root', + branch: 'aaa', + branches: [['foo', 'bar'], ['baz', 'qux']], + } + const context = { + logger, + options: { + ...globalConfig, + [step]: [ + { path, foo: 'BAR', ...extra } + ] + }, + cwd, + branch: { name: 'foo' }, + env: { GH_TOKEN: token } + } + + const config = await resolveConfig(pluginConfig, context, path, step) + + expect(config).toEqual({ + src: 'docsdocs', + dst: 'root', + enterprise: true, + ciBranch: 'foo', + docsBranch: 'bar', + msg: 'doc update', + token, + repo: `https://${token}@enterprise.com/org/repo.git`, + pullTagsBranch: 'foo' + }) + }) + it('fills empty values with defaults', async () => { const step = 'publish' const path = PLUGIN_PATH @@ -159,7 +207,7 @@ describe('config', () => { delete process.env.DEBUG expect(config).toEqual({ - branch: DEFAULT_BRANCH, + docsBranch: DEFAULT_BRANCH, dst: DEFAULT_DST, enterprise: DEFAULT_ENTERPRISE, msg: DEFAULT_MSG, @@ -186,6 +234,7 @@ describe('config', () => { logger, cwd, env: {}, + branch: {name: 'master'}, options: { branch: 'master', branches: [], @@ -232,7 +281,8 @@ describe('config', () => { const config = await resolveConfig(pluginConfig, context, path, step) expect(config).toEqual({ - branch: DEFAULT_BRANCH, + docsBranch: DEFAULT_BRANCH, + ciBranch: 'master', dst: DEFAULT_DST, enterprise: true, msg: DEFAULT_MSG, diff --git a/src/test/ts/ghpages.ts b/src/test/ts/ghpages.ts index a7f9d16..29ae92a 100644 --- a/src/test/ts/ghpages.ts +++ b/src/test/ts/ghpages.ts @@ -33,7 +33,8 @@ describe('ghpages', () => { cwd: 'stub', src: 'stub', dst: 'stub', - branch: 'stub', + ciBranch: 'stub', + docsBranch: 'stub', msg: 'stub' } diff --git a/src/test/ts/index.ts b/src/test/ts/index.ts index 685fdce..1d55675 100644 --- a/src/test/ts/index.ts +++ b/src/test/ts/index.ts @@ -80,7 +80,7 @@ describe('index', () => { const result = await verifyConditions(pluginConfig, context) expect(pluginConfig).toEqual({ - branch: DEFAULT_BRANCH, + docsBranch: DEFAULT_BRANCH, msg: DEFAULT_MSG, dst: DEFAULT_DST, src: DEFAULT_SRC,