"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    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) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SiteDeployManager = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const simple_git_1 = __importDefault(require("simple-git"));
const gh_pages_1 = __importDefault(require("gh-pages"));
const gitUtil = __importStar(require("../utils/git"));
const logger = __importStar(require("../utils/logger"));
const constants_1 = require("./constants");
/**
 * Handles the deployment of the generated site to GitHub Pages or other configured remote repositories.
 */
class SiteDeployManager {
    constructor(rootPath, outputPath) {
        this.rootPath = rootPath;
        this.outputPath = outputPath;
    }
    deploy(ciTokenVar) {
        const defaultDeployConfig = {
            branch: 'gh-pages',
            message: 'Site Update.',
            repo: '',
            remote: 'origin',
        };
        process.env.NODE_DEBUG = 'gh-pages';
        return this.generateDepUrl(ciTokenVar, defaultDeployConfig);
    }
    /**
     * Helper function for deploy(). Returns the ghpages link where the repo will be hosted.
     */
    generateDepUrl(ciTokenVar, defaultDeployConfig) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.siteConfig) {
                throw new Error('Site config not initialized');
            }
            const depOptions = yield this.getDepOptions(ciTokenVar, defaultDeployConfig, gh_pages_1.default.publish);
            try {
                return yield SiteDeployManager.getDepUrl(depOptions);
            }
            finally {
                gh_pages_1.default.clean();
            }
        });
    }
    /**
     * Helper function for deploy(). Set the options needed to be used by ghpages.publish.
     */
    getDepOptions(ciTokenVar, defaultDeployConfig, publish) {
        return __awaiter(this, void 0, void 0, function* () {
            const basePath = this.siteConfig.deploy.baseDir || this.outputPath;
            if (!fs_extra_1.default.existsSync(basePath)) {
                throw new Error('The site directory does not exist. Please build the site first before deploy.');
            }
            const options = {
                branch: this.siteConfig.deploy.branch || defaultDeployConfig.branch,
                message: this.siteConfig.deploy.message || defaultDeployConfig.message,
                repo: this.siteConfig.deploy.repo || defaultDeployConfig.repo,
                remote: defaultDeployConfig.remote,
            };
            options.message = options.message.concat(' [skip ci]');
            // Globally set Cache Directory to /node_modules/.cache for gh-pages
            if (!process.env.CACHE_DIR || ['true', 'false', '1', '0'].includes(process.env.CACHE_DIR)) {
                const cacheDirectory = path_1.default.join(this.rootPath, 'node_modules', '.cache');
                fs_extra_1.default.emptydirSync(path_1.default.join(cacheDirectory, 'gh-pages'));
                process.env.CACHE_DIR = cacheDirectory;
            }
            if (ciTokenVar) {
                const ciToken = constants_1._.isBoolean(ciTokenVar) ? 'GITHUB_TOKEN' : ciTokenVar;
                if (!process.env[ciToken]) {
                    throw new Error(`The environment variable ${ciToken} does not exist.`);
                }
                const githubToken = process.env[ciToken];
                let repoSlug;
                if (process.env.TRAVIS) {
                    repoSlug = SiteDeployManager.extractRepoSlug(options.repo, process.env.TRAVIS_REPO_SLUG);
                    options.user = {
                        name: 'Deployment Bot',
                        email: 'deploy@travis-ci.org',
                    };
                }
                else if (process.env.APPVEYOR) {
                    repoSlug = SiteDeployManager.extractRepoSlug(options.repo, process.env.APPVEYOR_REPO_NAME);
                    options.user = {
                        name: 'AppVeyorBot',
                        email: 'deploy@appveyor.com',
                    };
                }
                else if (process.env.GITHUB_ACTIONS) {
                    // Set cache folder to a location Github Actions can find.
                    process.env.CACHE_DIR = path_1.default.join(process.env.GITHUB_WORKSPACE || '.cache');
                    repoSlug = SiteDeployManager.extractRepoSlug(options.repo, process.env.GITHUB_REPOSITORY);
                    options.user = {
                        name: 'github-actions',
                        email: 'github-actions@github.com',
                    };
                }
                else if (process.env.CIRCLECI) {
                    repoSlug = SiteDeployManager.extractRepoSlug(options.repo, `${process.env.CIRCLE_PROJECT_USERNAME}/${process.env.CIRCLE_PROJECT_REPONAME}`);
                    options.user = {
                        name: 'circleci-bot',
                        email: 'deploy@circleci.com',
                    };
                }
                else {
                    throw new Error('-c/--ci should only be run in CI environments.');
                }
                options.repo = `https://x-access-token:${githubToken}@github.com/${repoSlug}.git`;
            }
            // Waits for the repo to be updated.
            yield publish(basePath, options);
            return options;
        });
    }
    /**
     * Extract repo slug from user-specified repo URL so that we can include the access token
     */
    static extractRepoSlug(repo, ciRepoSlug) {
        if (!repo) {
            return ciRepoSlug;
        }
        const repoSlugRegex = /github\.com[:/]([\w-]+\/[\w-.]+)\.git$/;
        const repoSlugMatch = repoSlugRegex.exec(repo);
        if (!repoSlugMatch) {
            throw new Error('-c/--ci expects a GitHub repository.\n'
                + `The specified repository ${repo} is not valid.`);
        }
        const [, repoSlug] = repoSlugMatch;
        return repoSlug;
    }
    /**
     * Helper function for deploy().
     */
    static getDepUrl(options) {
        const git = (0, simple_git_1.default)({ baseDir: process.cwd() });
        return SiteDeployManager.getDeploymentUrl(git, options);
    }
    /**
     * Gets the deployed website's url, returning null if there was an error retrieving it.
     */
    static getDeploymentUrl(git, options) {
        return __awaiter(this, void 0, void 0, function* () {
            const HTTPS_PREAMBLE = 'https://';
            const SSH_PREAMBLE = 'git@github.com:';
            const GITHUB_IO_PART = 'github.io';
            // https://<name|org name>.github.io/<repo name>/
            function constructGhPagesUrl(remoteUrl) {
                if (!remoteUrl) {
                    return null;
                }
                const parts = remoteUrl.split('/');
                if (remoteUrl.startsWith(HTTPS_PREAMBLE)) {
                    // https://github.com/<name|org>/<repo>.git (HTTPS)
                    const repoNameWithExt = parts[parts.length - 1];
                    const repoName = repoNameWithExt.substring(0, repoNameWithExt.lastIndexOf('.'));
                    const name = parts[parts.length - 2].toLowerCase();
                    return `https://${name}.${GITHUB_IO_PART}/${repoName}`;
                }
                else if (remoteUrl.startsWith(SSH_PREAMBLE)) {
                    // git@github.com:<name|org>/<repo>.git (SSH)
                    const repoNameWithExt = parts[parts.length - 1];
                    const repoName = repoNameWithExt.substring(0, repoNameWithExt.lastIndexOf('.'));
                    const name = parts[0].substring(SSH_PREAMBLE.length);
                    return `https://${name}.${GITHUB_IO_PART}/${repoName}`;
                }
                return null;
            }
            const { remote, branch, repo } = options;
            const cnamePromise = gitUtil.getRemoteBranchFile(git, 'blob', remote, branch, 'CNAME');
            const remoteUrlPromise = gitUtil.getRemoteUrl(git, remote);
            const promises = [cnamePromise, remoteUrlPromise];
            try {
                const promiseResults = yield Promise.all(promises);
                const generateGhPagesUrl = (results) => {
                    const cname = results[0];
                    const remoteUrl = results[1];
                    if (cname) {
                        return cname.trim();
                    }
                    else if (repo) {
                        return constructGhPagesUrl(repo);
                    }
                    return constructGhPagesUrl(remoteUrl.trim());
                };
                return generateGhPagesUrl(promiseResults);
            }
            catch (err) {
                logger.error(err);
                return null;
            }
        });
    }
}
exports.SiteDeployManager = SiteDeployManager;
//# sourceMappingURL=SiteDeployManager.js.map