mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
Updates files outside of x-pack to be triple-licensed under Elastic License 2.0, AGPL 3.0, or SSPL 1.0.
176 lines
4.5 KiB
TypeScript
176 lines
4.5 KiB
TypeScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the "Elastic License
|
|
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
|
* Public License v 1"; you may not use this file except in compliance with, at
|
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
|
*/
|
|
|
|
import Fs from 'fs';
|
|
import Os from 'os';
|
|
import Path from 'path';
|
|
import Rl from 'readline';
|
|
|
|
import Chalk from 'chalk';
|
|
import execa from 'execa';
|
|
import { ToolingLog } from '@kbn/tooling-log';
|
|
|
|
import { quietFail } from './error';
|
|
|
|
function lines(read: NodeJS.ReadableStream) {
|
|
return Rl.createInterface({
|
|
input: read,
|
|
crlfDelay: Infinity,
|
|
});
|
|
}
|
|
|
|
function getGithubBase(log: ToolingLog) {
|
|
try {
|
|
const originUrl = execa.sync('git', ['remote', 'get-url', 'origin'], {
|
|
encoding: 'utf8',
|
|
}).stdout;
|
|
|
|
if (originUrl.startsWith('git@')) {
|
|
log.warning('using ssh urls for Github repos');
|
|
return `git@github.com:`;
|
|
}
|
|
} catch {
|
|
// noop
|
|
}
|
|
|
|
if (process.env.GITHUB_TOKEN) {
|
|
log.warning('using https urls for Github repos (with token)');
|
|
return `https://token:${process.env.GITHUB_TOKEN}@github.com/`;
|
|
}
|
|
|
|
log.warning('using https urls for Github repos');
|
|
return `https://github.com/`;
|
|
}
|
|
|
|
export class Repo {
|
|
constructor(
|
|
private readonly log: ToolingLog,
|
|
private readonly name: string,
|
|
private readonly dir: string,
|
|
private readonly githubBase: string
|
|
) {}
|
|
|
|
resolve(...segs: string[]) {
|
|
return Path.resolve(this.dir, ...segs);
|
|
}
|
|
|
|
exists() {
|
|
if (!Fs.existsSync(this.dir)) {
|
|
return false;
|
|
}
|
|
|
|
if (!Fs.statSync(this.dir).isDirectory()) {
|
|
throw new Error(`[${this.name}] directory exists but it's not a directory like it should be`);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
async run(cmd: string, args: string[], opts: { desc: string; showOutput?: boolean }) {
|
|
try {
|
|
if (!opts.showOutput) {
|
|
await execa(cmd, args, {
|
|
cwd: this.dir,
|
|
maxBuffer: Infinity,
|
|
});
|
|
return;
|
|
}
|
|
|
|
await this.log.indent(4, async () => {
|
|
const proc = execa(cmd, args, {
|
|
cwd: this.dir,
|
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
});
|
|
|
|
await Promise.all([
|
|
(async () => {
|
|
for await (const line of lines(proc.stdout!)) {
|
|
this.log.write(Chalk.dim('out '), line);
|
|
}
|
|
})(),
|
|
(async () => {
|
|
for await (const line of lines(proc.stderr!)) {
|
|
this.log.write(Chalk.red('err '), line);
|
|
}
|
|
})(),
|
|
new Promise((resolve, reject) => {
|
|
proc.once('exit', resolve).once('exit', reject);
|
|
}),
|
|
]);
|
|
});
|
|
} catch (error) {
|
|
this.log.debug(
|
|
`Failed to run [${opts.desc}] in [${this.name}]`,
|
|
opts.showOutput ? error : undefined
|
|
);
|
|
|
|
throw quietFail(`${this.name}: ${opts.desc} failed`);
|
|
}
|
|
}
|
|
|
|
async update() {
|
|
try {
|
|
this.log.info('updating', this.name);
|
|
await this.run('git', ['reset', '--hard'], { desc: 'git reset --hard' });
|
|
await this.run(
|
|
'git',
|
|
[
|
|
'clean',
|
|
'-fdx',
|
|
...(this.name === 'elastic/docs.elastic.dev'
|
|
? ['-e', '/.docsmobile', '-e', '/node_modules']
|
|
: []),
|
|
],
|
|
{ desc: 'git clean -fdx' }
|
|
);
|
|
await this.run('git', ['pull'], { desc: 'git pull' });
|
|
} catch {
|
|
quietFail(`failed to update ${this.name}`);
|
|
}
|
|
}
|
|
|
|
async clone() {
|
|
try {
|
|
this.log.info('cloning', this.name);
|
|
Fs.mkdirSync(this.dir, { recursive: true });
|
|
const depth = process.env.CI ? ['--depth', '1'] : [];
|
|
await this.run('git', ['clone', ...depth, `${this.githubBase}${this.name}.git`, '.'], {
|
|
desc: 'git clone ...',
|
|
});
|
|
} catch {
|
|
quietFail(`Failed to clone ${this.name}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export class Repos {
|
|
githubBase: string;
|
|
repoDir = Path.resolve(Os.userInfo().homedir, '.cache/next-docs/repos');
|
|
|
|
constructor(private readonly log: ToolingLog) {
|
|
this.githubBase = getGithubBase(this.log);
|
|
}
|
|
|
|
async init(repoName: string) {
|
|
const repo = new Repo(
|
|
this.log,
|
|
repoName,
|
|
Path.resolve(this.repoDir, repoName),
|
|
this.githubBase
|
|
);
|
|
|
|
if (repo.exists()) {
|
|
await repo.update();
|
|
} else {
|
|
await repo.clone();
|
|
}
|
|
|
|
return repo;
|
|
}
|
|
}
|