"use strict";
/**
 * Script automates versioning/publishing process of packages.
 * It allows us to introduce such type of dependencies like snapshots.
 * We name dependency as `snapshot` if its version looks like: `x.x.x-<branch-name`.
 * We name dependency as `release` if its version does not have suffix: `x.x.x`.
 *
 * Environmental requirements.
 * It is necessary that at the time of launching the script in the root of the project there was a .npmrc file
 * containing an access token at the time of launching the script.
 *
 * Parameters:
 *  --dist      (optional)  You can specify destination of package you want to publish.
 *                          Default: './dist' or current directory if no ./dist is there.
 *
 * @type {string}
 * @see {@link https://www.notion.so/arrivalms/Versioning-5bf1876eb2f142339d719f818cc2250c}
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const fs = require("fs");
const childProcess = require("child_process");
const argument_parser_1 = require("@eigenspace/argument-parser");
const exists = require('npm-exists');
const exec = childProcess.execSync;
const argParser = new argument_parser_1.ArgumentParser();
const argv = argParser.get(process.argv.slice(2));
const projectPaths = argv.get('projectPaths') || ['/'];
let currentBranch = getCurrentBranchName();
if (!Boolean(currentBranch)) {
    // eslint-disable-next-line no-console
    console.log('Current branch is undefined!');
    process.exit(1);
}
// eslint-disable-next-line no-console,no-console
console.log('branch:', currentBranch);
const projectPathsThatShouldBeIncrementedInDevBranch = [];
projectPaths.forEach((projectPath) => __awaiter(this, void 0, void 0, function* () { return yield incrementPackagesInTargetBranch(projectPath); }));
push();
checkout('dev');
merge('master');
projectPathsThatShouldBeIncrementedInDevBranch.forEach(projectPath => incrementPackagesInDev(projectPath));
push();
// Functions
// -----------
function incrementPackagesInTargetBranch(projectPath) {
    return __awaiter(this, void 0, void 0, function* () {
        const currentDir = `${process.cwd()}${projectPath}`;
        const packageJsonPath = path.join(currentDir, 'package.json');
        const packageJson = require(packageJsonPath);
        // Get dependency suffix (branch name)
        const { name, version } = packageJson;
        const distDir = path.join(currentDir, 'dist');
        const distParam = argv.get('dist');
        const dist = distParam || fs.existsSync(distDir) && distDir || currentDir;
        // eslint-disable-next-line no-console
        console.log('package to publish:', dist);
        // We consider snapshot as any non-master dependency version.
        // Every snapshot dependency version should be prerelease version that has suffix contains branch name
        const isSnapshotVersion = currentBranch !== 'master';
        const suffix = prepareSuffix(isSnapshotVersion ? `-${currentBranch}` : '');
        const fullVersion = `${name}@${version}${suffix}`;
        // If branch name is not master, i.e. there is no suffix
        if (isSnapshotVersion) {
            // eslint-disable-next-line no-console
            console.log('start publishing snapshot package...');
            // Then remove dependency from registry
            run(`npm unpublish ${fullVersion}`);
            publish(dist, `${version}${suffix}`);
            if (dist === currentDir) {
                // Remove snapshot version from package.json
                run('git checkout package.json');
            }
        }
        else {
            // eslint-disable-next-line no-console
            console.log('start publishing release package...');
            const projectExists = exists(name);
            // If it is production version (master), we check it exists in npm registry
            const versionInRegistry = projectExists && run(`npm view ${fullVersion} version`);
            if (versionInRegistry) {
                // eslint-disable-next-line no-console
                console.log(`package '${fullVersion}' exists in registry`);
                incrementVersionAndCommit(packageJsonPath, dist);
            }
            projectPathsThatShouldBeIncrementedInDevBranch.push(projectPath);
            publish(dist);
        }
    });
}
function incrementPackagesInDev(projectPath) {
    const currentDir = `${process.cwd()}${projectPath}`;
    const packageJsonPath = path.join(currentDir, 'package.json');
    const distDir = path.join(currentDir, 'dist');
    const distParam = argv.get('dist');
    const dist = distParam || fs.existsSync(distDir) && distDir || currentDir;
    incrementVersionAndCommit(packageJsonPath, dist);
}
function run(command) {
    // eslint-disable-next-line no-console
    console.log('run command:', command);
    const stdout = exec(command, { encoding: 'utf8' });
    // eslint-disable-next-line no-console
    console.log(stdout);
    return stdout;
}
function publish(dist, packageVersion) {
    if (packageVersion) {
        setVersionToDistPackage(packageVersion, dist);
    }
    run(`npm publish ${dist}`);
}
function incrementVersionAndCommit(packageJsonPath, dist) {
    // We getting new package.json to get always actual package.json for case when we change our branch.
    // For example, we move from master to dev. There at dev branch package.json will be different.
    const parsedPackageJsonFile = require(packageJsonPath);
    // Same with version. Always getting actual version of package.
    const { name, version: packageVersion } = parsedPackageJsonFile;
    const [major, minor, patch] = packageVersion.split('.');
    const incrementedVersion = `${major}.${minor}.${Number(patch) + 1}`;
    // eslint-disable-next-line no-console
    console.log('incremented version:', incrementedVersion);
    parsedPackageJsonFile.version = incrementedVersion;
    const indent = 4;
    const packageJsonStringified = JSON.stringify(parsedPackageJsonFile, undefined, indent);
    fs.writeFileSync(packageJsonPath, packageJsonStringified);
    fs.writeFileSync(`${dist}/package.json`, packageJsonStringified);
    run(`git commit --all --no-verify --message "auto/ci: set version of ${name} to ${incrementedVersion}"`);
}
function push() {
    run(`git push --no-verify origin ${currentBranch}`);
}
function setVersionToDistPackage(packageVersion, dist) {
    // eslint-disable-next-line no-console
    console.log('update version in dist package.json to:', packageVersion);
    const distPackageJsonFile = readJsonFile(`${dist}/package.json`);
    distPackageJsonFile.version = packageVersion;
    const indent = 4;
    const packageJsonStringified = JSON.stringify(distPackageJsonFile, undefined, indent);
    fs.writeFileSync(`${dist}/package.json`, packageJsonStringified);
    // eslint-disable-next-line no-console
    console.log('version in dist package.json was successfully updated');
}
function checkout(branchName) {
    currentBranch = branchName;
    run('git fetch origin --progress --prune');
    run(`git checkout --track origin/${branchName}`);
}
function merge(branchName) {
    run(`git merge --no-ff ${branchName}`);
}
function getCurrentBranchName() {
    const branchList = run('git branch');
    const branch = branchList.split('\n')
        .find(branchName => branchName.startsWith('*'));
    return (branch || '').replace('* ', '');
}
function readJsonFile(filename) {
    return JSON.parse(fs.readFileSync(filename, 'utf8'));
}
function prepareSuffix(rawSuffix) {
    return rawSuffix.replace(/\//g, '-');
}
//# sourceMappingURL=publish.js.map