Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/FoxxMD/komodo-import. Import existing compose stacks into Komodo foxxmd.github.io/komodo-import
Something went wrong. Try again.
6.7 kB · 161 lines
TypeScript
at gitBranch
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161import { AnyStackConfig, FilesOnServerConfig, GitStackConfig } from "../../common/infrastructure/config/stackConfig.js";import { TomlStack } from "../../common/infrastructure/tomlObjects.js";import { promises } from 'fs';import { pathExistsAndIsReadable, readDirectories } from "../../common/utils/io.js";import { childLogger, Logger } from "@foxxmd/logging";import { isUndefinedOrEmptyString, parseBool } from "../../common/utils/utils.js";import { detectGitRepo, GitRepoData, komodoRepoFromRemote, matchGitDataWithKomodo } from "../../common/utils/git.js";import { buildGitStack } from "./gitStack.js";import { join as joinPath, parse, ParsedPath } from 'path';import { DEFAULT_COMPOSE_GLOB, DEFAULT_ENV_GLOB } from "./stackUtils.js";import { buildFileStack } from "./filesOnServer.js";import { SimpleError } from "../../common/errors.js";
export const buildStacksFromPath = async (path: string, options: AnyStackConfig, parentLogger: Logger): Promise<TomlStack[]> => {
const { composeFileGlob = DEFAULT_COMPOSE_GLOB, envFileGlob = DEFAULT_ENV_GLOB, } = options;
let stackOptions = options;
const logger = childLogger(parentLogger, 'Stacks'); let topDir: string; try { topDir = await promises.realpath(path); logger.info(`Top Dir: ${path} -> Resolved: ${topDir}`); pathExistsAndIsReadable(topDir) } catch (e) { throw new Error(`Could not access ${path}.${parseBool(process.env.IS_DOCKER) ? ' This is the path *in container* that is read so make sure you have mounted it on the host!' : ''}`); }
let stacksDir: string = topDir; if (!isUndefinedOrEmptyString(process.env.GIT_STACKS_DIR)) { try { stacksDir = await promises.realpath(process.env.GIT_STACKS_DIR); logger.info(`Git Stack Dir: ${stacksDir} -> Resolved: ${stacksDir}`); pathExistsAndIsReadable(stacksDir) } catch (e) { throw new Error(`Could not access ${stacksDir}.${parseBool(process.env.IS_DOCKER) ? ' This is the path *in container* that is read so make sure you have mounted it on the host!' : ''}`); } }
let stacks: TomlStack[] = [];
const dirs = await readDirectories(stacksDir); const folderPaths = dirs.map(x => joinPath(stacksDir, x));
let gitData: GitRepoData; try { gitData = await detectGitRepo(path); } catch (e) { if (e instanceof SimpleError) { logger.debug(e.message); } else { throw e; } }
logger.info(`Processing Stacks for ${dirs.length} folders in ${stacksDir}:\n${dirs.join('\n')}`); logger.info(`Compose File Glob: ${composeFileGlob}`); logger.info(`Env Glob: ${envFileGlob}`);
let hostParentPathVerified = false;
if (gitData !== undefined) {
logger.info(`Detected top-level dir ${topDir} is a Git repo: Branch ${gitData[0].branch} | Remote ${gitData[1].remote} | URL ${gitData[1].url}`); logger.info('Will treat this as a monorepo -- all subfolders will be built as Git-Repo Stacks using the same repo with Run Directory relative to repo root.');
let gitStackConfig: Partial<GitStackConfig> = { inMonorepo: true } try { const [provider, linkedRepo, repoHint] = await matchGitDataWithKomodo(gitData); if (repoHint !== undefined) { logger.warn(`All Stacks will be built without a linked repo: ${repoHint}`); } const [domain, repo] = komodoRepoFromRemote(gitData[1].url) if (repo === undefined) { gitStackConfig = { ...options, git_provider: provider?.domain ?? domain, git_account: provider?.username, repo }; } else { gitStackConfig = { ...options, linked_repo: linkedRepo.name, } } } catch (e) { throw new Error('Cannot use top-level git for Stacks', { cause: e }); }
stackOptions = { ...stackOptions, ...gitStackConfig, writeEnv: parseBool(process.env.GIT_WRITE_ENV, false), inMonorepo: true } } else { logger.info('Top-level dir is not a git repo -- subfolders will be individually detected as Git repo or files-on-server Stacks.'); }
for (const f of folderPaths) {
const pathInfo: ParsedPath = parse(f); const folderLogger = childLogger(logger, `${pathInfo.name}${pathInfo.ext !== '' ? pathInfo.ext : ''}`);
if (gitData !== undefined) { try { stacks.push(await buildGitStack(f, { ...stackOptions, logger, hostParentPath: stacksDir === topDir ? undefined : stacksDir.replace(topDir, '').replace(/^\//, '') })); } catch (e) { folderLogger.error(new Error(`Unable to build Git Stack for folder ${f}`, { cause: e })); } } else {
try { stacks.push(await buildGitStack(f, { inMonorepo: false, writeEnv: parseBool(process.env.GIT_WRITE_ENV, false), ...options, logger })); continue; } catch (e) { if (e instanceof SimpleError) { if (e.message.includes('does not have a .git folder')) { folderLogger.debug('Falling back to Files-On-Server, not a git repo'); } else { folderLogger.verbose(`Falling back to Files-On-Server => ${e.message}`); } } else { folderLogger.error(new Error(`Unable to build Git Stack for folder ${f}`, { cause: e })); continue; } }
const opts = options as FilesOnServerConfig; if (!hostParentPathVerified) { if (isUndefinedOrEmptyString(opts.hostParentPath)) { throw new Error('env HOST_PARENT_PATH is not set'); } hostParentPathVerified = true; } try { stacks.push(await buildFileStack(f, { ...opts, logger })); } catch (e) { folderLogger.error(new Error(`Unable to build Files-On-Server Stack for folder ${f}`, { cause: e })); } } } return stacks;}