1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-23 22:36:32 +02:00
Files
joplin/packages/tools/buildServerDocker.ts

167 lines
5.3 KiB
TypeScript

import { rootDir } from './tool-utils';
import * as moment from 'moment';
import { execCommand } from '@joplin/utils';
interface Argv {
dryRun?: boolean;
pushImages?: boolean;
repository?: string;
tagName?: string;
platform?: string;
source?: string;
addLatestTag?: boolean;
dockerFile?: string;
}
function parseArgv(): Argv {
return require('yargs')
.scriptName('yarn buildServerDocker')
.usage('$0 --repository OWNER/IMAGE [args]')
.option('dockerFile', {
describe: 'Dockerfile - either Dockerfile.server or Dockerfile.transcribe',
demandOption: true,
type: 'string',
})
.option('repository', {
describe: 'Target image repository. Usually in format `OWNER/NAME`',
demandOption: true,
type: 'string',
})
.option('tagName', {
describe: 'Base image tag. Usually should be in format `server-v1.2.3` or `server-v1.2.3-beta`. The latest `server-v*` git tag will be used by default.',
type: 'string',
})
.option('addLatestTag', {
describe: 'Add `latest` tag even for pre-release images.',
type: 'boolean',
default: false,
})
.option('platform', {
describe: 'Comma separated list of target image platforms. E.g. `linux/amd64` or `linux/amd64,linux/arm64`',
type: 'string',
default: 'linux/amd64',
})
.option('source', {
describe: 'Source Git repository for the images.',
type: 'string',
default: 'https://github.com/laurent22/joplin.git',
})
.option('pushImages', {
describe: 'Publish images to target repository.',
type: 'boolean',
default: false,
})
.option('dryRun', {
describe: 'Do not call docker, just show command instead.',
type: 'boolean',
default: false,
})
.help()
.argv as Argv;
}
export function getVersionFromTag(tagName: string, isPreRelease: boolean): string {
const s = tagName.split('-');
const mainVersion = s[1].replace(/^(v)/, '');
const metaComponents = s.slice(2).filter(item => item !== 'beta');
// Append `git describe` components for pre release images. Mostly for case without `tagName` arg
const suffix = isPreRelease ? `-beta${metaComponents.length > 0 ? `.${metaComponents.join('.')}` : ''}` : '';
return mainVersion + suffix;
}
export function getIsPreRelease(_tagName: string): boolean {
// For now we only create pre-releases from CI. It's after, once the release
// has been proven stable, that it is tagged as "latest".
return false;
// return tagName.indexOf('-beta') > 0;
}
async function main() {
const argv = parseArgv();
if (!argv.tagName) console.info('No `--tag-name` was specified. A latest git tag will be used instead.');
console.info('Raw arguments:', argv);
const dryRun = argv.dryRun;
const addLatestTag = argv.addLatestTag;
const dockerFile = argv.dockerFile;
const pushImages = argv.pushImages;
const repository = argv.repository;
const tagName = argv.tagName || `server-${await execCommand('git describe --tags --match v*', { showStdout: false })}`;
const platform = argv.platform;
const source = argv.source;
const architecture = argv.platform.split('/')[1];
const isPreRelease = getIsPreRelease(tagName);
const imageVersion = getVersionFromTag(tagName, isPreRelease);
const buildDate = moment(new Date().getTime()).format('YYYY-MM-DDTHH:mm:ssZ');
let revision = '';
try {
revision = await execCommand('git rev-parse --short HEAD', { showStdout: false });
} catch (error) {
console.info('Could not get git commit: metadata revision field will be empty');
}
const buildArgs = [];
buildArgs.push(`BUILD_DATE="${buildDate}"`);
buildArgs.push(`REVISION="${revision}"`);
buildArgs.push(`VERSION="${imageVersion}"`);
buildArgs.push(`SOURCE="${source}"`);
const dockerTags: string[] = [];
const versionParts = imageVersion.split('.');
const patchVersionPart = versionParts[2].split('-')[0];
dockerTags.push(isPreRelease ? 'latest-beta' : 'latest');
dockerTags.push(versionParts[0] + (isPreRelease ? '-beta' : ''));
dockerTags.push(`${versionParts[0]}.${versionParts[1]}${isPreRelease ? '-beta' : ''}`);
dockerTags.push(`${versionParts[0]}.${versionParts[1]}.${patchVersionPart}${isPreRelease ? '-beta' : ''}`);
if (dockerTags.indexOf(imageVersion) < 0) {
dockerTags.push(imageVersion);
}
if (addLatestTag && dockerTags.indexOf('latest') < 0) {
dockerTags.push('latest');
}
process.chdir(rootDir);
console.info(`Running from: ${process.cwd()}`);
console.info('dockerFile:', dockerFile);
console.info('repository:', repository);
console.info('tagName:', tagName);
console.info('platform:', platform);
console.info('pushImages:', pushImages);
console.info('imageVersion:', imageVersion);
console.info('isPreRelease:', isPreRelease);
console.info('Docker tags:', dockerTags.join(', '));
const cliArgs = ['--progress=plain'];
cliArgs.push(`--platform ${platform}`);
cliArgs.push(...dockerTags.map(tag => `--tag "${repository}:${architecture}-${tag}"`));
cliArgs.push(...buildArgs.map(arg => `--build-arg ${arg}`));
if (pushImages) {
cliArgs.push('--push');
}
cliArgs.push(`--file ${dockerFile}`);
cliArgs.push('.');
const dockerCommand = `docker buildx build ${cliArgs.join(' ')}`;
console.info('exec:', dockerCommand);
if (dryRun) {
return;
}
await execCommand(dockerCommand);
}
if (require.main === module) {
// eslint-disable-next-line promise/prefer-await-to-then
main().catch((error) => {
console.error('Fatal error');
console.error(error);
process.exit(1);
});
}