From bd37b1858935f9e6c7e580d5819b751d8c3bcfe4 Mon Sep 17 00:00:00 2001 From: alexrr2iggs Date: Thu, 11 Jan 2024 12:22:51 +0100 Subject: [PATCH] B.O.H --- .gitignore | 4 +- scripts/check.ts | 39 ++++ scripts/generate_test_files.ts | 19 ++ scripts/mk_deb_pkg.ts | 3 + scripts/mk_deb_pkg_mod.ts | 124 ++++++++++ scripts/mk_tag.ts | 117 ++++++++++ scripts/set_build_env.ts | 9 + scripts/set_up_test_env.ts | 29 +++ scripts/utils.ts | 291 ++++++++++++++++++++++++ src/errors/invalid_semver.ts | 1 + src/errors/mc_server_download_failed.ts | 1 + src/errors/mc_version_not_found.ts | 1 + src/types/conf.ts | 1 + src/types/packages.ts | 1 + src/types/version_manifest_v2.ts | 1 + 15 files changed, 639 insertions(+), 2 deletions(-) create mode 100755 scripts/check.ts create mode 100755 scripts/generate_test_files.ts create mode 100755 scripts/mk_deb_pkg.ts create mode 100755 scripts/mk_deb_pkg_mod.ts create mode 100755 scripts/mk_tag.ts create mode 100644 scripts/set_build_env.ts create mode 100755 scripts/set_up_test_env.ts create mode 100644 scripts/utils.ts diff --git a/.gitignore b/.gitignore index 5b4e71c..9a2e1ee 100644 --- a/.gitignore +++ b/.gitignore @@ -134,6 +134,6 @@ dist #deno deno.lock -scripts .tmp -tests/tmp/ \ No newline at end of file +tests/tmp/ +.history \ No newline at end of file diff --git a/scripts/check.ts b/scripts/check.ts new file mode 100755 index 0000000..1d8039b --- /dev/null +++ b/scripts/check.ts @@ -0,0 +1,39 @@ +#!/usr/bin/env -S deno run -A +/** + * script to check code quality and consistency + */ +import { getEmptyFiles, getSkipTestSrcs, getsMissingTestSrcs, SRC_DIR, TESTS_DIR } from './utils.ts'; + +let exitCode = 0; + +// check if there are src files with the @skip-test comment +const skipTestSrcFiles = getSkipTestSrcs(); +if (skipTestSrcFiles.length > 0) { + for (const srcFile of skipTestSrcFiles) { + console.log(`%c[SKIP TEST] %c${srcFile}`, 'color: orange', 'color: yellow'); + } +} + +// check if there are src files WITHOUT TEST files +const srcFilesWithoutTestFile = getsMissingTestSrcs(); +if (srcFilesWithoutTestFile.length > 0) { + for (const srcFile of srcFilesWithoutTestFile) { + console.log(`%c[WITHOUT TEST] %c${srcFile}`, 'color: red', 'color: #ff4900'); + } + exitCode = 1; +} + +// check if there are EMPTY TS FILES, in src or test +const emptyTsFiles = [...getEmptyFiles(SRC_DIR, 'ts'), ...getEmptyFiles(TESTS_DIR, 'test.ts')]; +if (emptyTsFiles.length > 0) { + for (const tsFile of emptyTsFiles) { + console.log(`%c[EMPTY TS FILE] %c${tsFile}`, 'color: red', 'color: gray'); + } + exitCode = 1; +} + +if (exitCode === 0) { + console.log(`%c[CHECK PASS]`, 'color: green'); +} else { + Deno.exit(exitCode); +} diff --git a/scripts/generate_test_files.ts b/scripts/generate_test_files.ts new file mode 100755 index 0000000..403b007 --- /dev/null +++ b/scripts/generate_test_files.ts @@ -0,0 +1,19 @@ +#!/usr/bin/env -S deno run -A +/** script to generate an empty .test.ts file for each .ts file that doesnt have one*/ +import { writeFileAndDir } from 'utils/fs.ts'; +import { getSkipTestSrcs, sourceFilePathToTestFilePath } from './utils.ts'; + +const skipTestSrcFiles = getSkipTestSrcs(); + +if (skipTestSrcFiles.length > 0) { + for (const srcFile of skipTestSrcFiles) { + console.log(`%c[SKIP TEST] %c${srcFile}`, 'color: orange', 'color: yellow'); + } +} + +for (const sourceFilePath of getSkipTestSrcs()) { + const testFilePath = sourceFilePathToTestFilePath(sourceFilePath); + + console.log(`%c[GENERATE TEST] %c${testFilePath}`, 'color: green', 'color: yellow'); + writeFileAndDir(testFilePath, ''); +} diff --git a/scripts/mk_deb_pkg.ts b/scripts/mk_deb_pkg.ts new file mode 100755 index 0000000..e4596c3 --- /dev/null +++ b/scripts/mk_deb_pkg.ts @@ -0,0 +1,3 @@ +#!/usr/bin/env -S deno run --allow-read --allow-write --allow-env --allow-run +import { mkDebPkg } from './mk_deb_pkg_mod.ts'; +await mkDebPkg(); diff --git a/scripts/mk_deb_pkg_mod.ts b/scripts/mk_deb_pkg_mod.ts new file mode 100755 index 0000000..f1bce4c --- /dev/null +++ b/scripts/mk_deb_pkg_mod.ts @@ -0,0 +1,124 @@ +/** ./set_build_env.ts it needs to be evaluated befor everething so should be at top*/ +import './set_build_env.ts'; + +import { log } from 'iggs-utils'; +import { join, resolve } from 'std/path/mod.ts'; +import { defaultConfig } from 'utils/config.ts'; +import { copyFileRecursive, silentRemove, writeFileAndDir } from 'utils/fs.ts'; +import { logger } from 'utils/logger.ts'; +import { CONFIG_FILE_NAME, DEFAULT_SERVER_PROPERTIES_PATH, SYS_CONFIG_FILE_PATH } from 'utils/paths.ts'; +import { pkgInfo } from '../src/utils/package_info.ts'; +import { exe } from './utils.ts'; + +// setting application logger level. '-s' (silent) is used to shut down logger. +logger.logLevel = Deno.args.includes('-s') ? log.LogLevel.OFF : log.LogLevel.TRACE; +logger.prefix = `[MK_DEB_PKG]`; + +/** + * Interface representing the structure of a Debian package's control file. + */ +interface DebianControlFile { + /** The unique identifier name of the package. */ + Package: string; + + /** The version of the package, following the Debian versioning scheme. */ + Version: string; + + /** The section to which the package belongs, such as 'utils', 'net', etc. */ + Section?: string; + + /** The priority of the package, indicating its importance. */ + Priority?: 'required' | 'important' | 'standard' | 'optional' | 'extra'; + + /** The architecture for which the package is built, like 'amd64', 'i386'. */ + Architecture: string; + + /** Packages that must be installed for this package to work. */ + Depends?: string; + + /** Packages that are recommended for enhanced functionality. */ + Recommends?: string; + + /** Packages that are suggested but not necessary. */ + Suggests?: string; + + /** Indicates that the package enhances the functionality of other packages. */ + Enhances?: string; + + /** Packages that are required to be configured before this package is unpacked. */ + PreDepends?: string; + + /** Lists packages that are incompatible with this package. */ + Breaks?: string; + + /** Lists packages that cannot be installed alongside this package. */ + Conflicts?: string; + + /** Indicates that this package replaces other packages. */ + Replaces?: string; + + /** Declares that this package provides the functionality of another package. */ + Provides?: string; + + /** The disk space required by the package in kilobytes. */ + 'Installed-Size'?: number; + + /** The name and email of the person or team responsible for the package. */ + Maintainer: string; + + /** A brief description of the package. */ + Description: string; + + /** URL of the homepage for the software or package. */ + Homepage?: string; + + /** Indicates the source packages used to build this package. */ + 'Built-Using'?: string; +} + +export async function mkDebPkg(): Promise { + const controlFile: DebianControlFile = { + Package: pkgInfo.name, + Version: pkgInfo.version, + Architecture: 'amd64', + Maintainer: pkgInfo.maintainer, + Description: pkgInfo.description, + Homepage: pkgInfo.homepage, + }; + + const controlFileContent = Object.entries(controlFile) + .reduce((prev, [key, value]) => `${prev}${key}: ${value}\n`, ''); + + logger.debug(`creating debian package`, '\n', controlFileContent); + + const LINUXx64_BIN_PATH = join(resolve('dist'), 'bin', 'linux', 'x64', pkgInfo.name); + exe('deno', 'compile', '--unstable', '--target=x86_64-unknown-linux-gnu', '-A', '--output=' + LINUXx64_BIN_PATH, './src/main.ts'); + + // generating deb package directories + const ASSETS_DIR = resolve('assets'); + const DEFAULT_CONFIG_FILE_PATH = resolve(ASSETS_DIR, 'defaults', CONFIG_FILE_NAME); + const DEFAULT_DEFAULT_SERVER_PROPERTIES_PATH = resolve(ASSETS_DIR, 'defaults', 'server.properties'); + + const PKG_DIR = resolve('dist', 'deb_package'); + const PKG_ROOT = resolve(PKG_DIR, pkgInfo.name); + const PKG_BIN_PATH = join(PKG_ROOT, 'usr', 'bin', 'misela'); + const PKG_CONTROL_FILE_PATH = join(PKG_ROOT, 'DEBIAN', 'control'); + const PKG_DOC_PATH = join(PKG_ROOT, 'usr', 'share', 'doc', pkgInfo.name, 'README.md'); + const PKG_SYS_CONFIG_FILE_PATH = join(PKG_ROOT, SYS_CONFIG_FILE_PATH); + const PKG_DEFAULT_SERVER_PROPERTIES_PATH = join(PKG_ROOT, DEFAULT_SERVER_PROPERTIES_PATH); + const DEB_PKG_PATH = resolve('dist', `${pkgInfo.name}_${pkgInfo.version}_linux_amd64.deb`); + + silentRemove(PKG_DIR, { recursive: true }); + writeFileAndDir(PKG_CONTROL_FILE_PATH, controlFileContent); + copyFileRecursive(LINUXx64_BIN_PATH, PKG_BIN_PATH); + copyFileRecursive('./README.md', PKG_DOC_PATH); + copyFileRecursive(DEFAULT_CONFIG_FILE_PATH, PKG_SYS_CONFIG_FILE_PATH); + copyFileRecursive(DEFAULT_DEFAULT_SERVER_PROPERTIES_PATH, PKG_DEFAULT_SERVER_PROPERTIES_PATH); + writeFileAndDir(PKG_DEFAULT_SERVER_PROPERTIES_PATH, JSON.stringify(defaultConfig, null, 4)); + + exe('dpkg-deb', '--build', PKG_ROOT, DEB_PKG_PATH); + + console.log('%csuccessfully created deb package!!! πŸΎπŸŽ‰πŸŽ‡', 'color:green'); + + return DEB_PKG_PATH; +} diff --git a/scripts/mk_tag.ts b/scripts/mk_tag.ts new file mode 100755 index 0000000..cd4bdd8 --- /dev/null +++ b/scripts/mk_tag.ts @@ -0,0 +1,117 @@ +#!/usr/bin/env -S deno run -A +import { log } from 'iggs-utils'; +import { logger } from 'utils/logger.ts'; +import { pkgInfo } from 'utils/package_info.ts'; +import { mkDebPkg } from './mk_deb_pkg_mod.ts'; +import { exe } from './utils.ts'; + +export interface GhRelease { + url: string; + assets_url: string; + upload_url: string; + html_url: string; + id: number; + author: Author; + node_id: string; + tag_name: string; + target_commitish: string; + name: string; + draft: boolean; + prerelease: boolean; + created_at: string; + published_at: string; + assets: object[]; + tarball_url: string; + zipball_url: string; + body: string; + reactions: Reactions; + mentions_count: number; +} + +export interface Author { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; +} + +export interface Reactions { + url: string; + total_count: number; + '+1': number; + '-1': number; + laugh: number; + hooray: number; + confused: number; + heart: number; + rocket: number; + eyes: number; +} + +logger.logLevel = log.LogLevel.TRACE; +logger.prefix = `[MK_TAG]`; + +// lint +logger.info('linting...'); +exe('deno', 'lint'); + +// format +logger.info('formatting...'); +exe('deno', 'fmt'); + +// do code checks +logger.info('checking...'); +exe('./scripts/check.ts'); + +// run tests +logger.info('testing...'); +exe('deno', 'task', 'test'); + +// check if tag exists +logger.info(`checking if Tag ${pkgInfo.version} exists...`); +await checkIfTagExists(); + +// build deb package +logger.info('building deb package...'); +const LINUX_BIN_PATH = await mkDebPkg(); + +// commit changes +logger.info('committing changes...'); +exe('git', 'commit', '-m', `tag ${pkgInfo.version}`); + +// tag the commit with the current version +logger.info(`tagging ${pkgInfo.version}...`); +exe('git', 'tag', pkgInfo.version); + +// push the tag +logger.info('pushing tag...'); +exe('git', 'push', 'origin', pkgInfo.version); + +//Upload deb backage as release assets +logger.info(`uploading ${LINUX_BIN_PATH} asset...`); +exe('gh', 'release', 'create', pkgInfo.version, LINUX_BIN_PATH); + +console.log('%csuccessfully togged!!! πŸΎπŸŽ‰πŸŽ‡', 'color:green'); + +async function checkIfTagExists() { + const tags: GhRelease[] = await fetch('https://api.github.com/repos/alexrr2iggs/minecraft_server_updater/releases').then((r) => r.json()); + const tagAlreadyExists = tags?.find((t: GhRelease) => t?.tag_name === pkgInfo.version); + if (tagAlreadyExists) { + console.warn(`Tag ${pkgInfo.version} already exists\nsee ${tagAlreadyExists.html_url}`); + Deno.exit(1); + } +} diff --git a/scripts/set_build_env.ts b/scripts/set_build_env.ts new file mode 100644 index 0000000..0ecba92 --- /dev/null +++ b/scripts/set_build_env.ts @@ -0,0 +1,9 @@ +/** + * This script is a simple workaround for ecmascript module import mechanism, that loads and evaluates modules in a top-down manner, + * which means it first loads and evaluates all import statements before executing the rest of the code in a module. + * + * Since the project relies on the deno's ".env" feature to determine the runing environment, with a default value of 'development'. + * + * take a look at utils/paths.ts + */ +Deno.env.set('DENO_ENV', 'compile_production'); diff --git a/scripts/set_up_test_env.ts b/scripts/set_up_test_env.ts new file mode 100755 index 0000000..82597f0 --- /dev/null +++ b/scripts/set_up_test_env.ts @@ -0,0 +1,29 @@ +#!/usr/bin/env -S deno run -A +import { log } from 'iggs-utils'; +import { defaultConfig } from 'utils/config.ts'; +import { writeFileAndDir } from 'utils/fs.ts'; +import { logger } from 'utils/logger.ts'; +import { DEFAULT_SERVER_PROPERTIES_PATH, SYS_CONFIG_FILE_PATH, USR_CONFIG_FILE_PATH } from 'utils/paths.ts'; +import { FAKE_SERVER_VERSION_MANIFEST_V2_URL } from '../tests/test_utils/fake_api_server.ts'; +Deno.env.set('DENO_ENV', 'development'); +logger.logLevel = log.LogLevel.TRACE; + +/** + * error: NotFound: No such file or directory (os error 2): open '/home//.development/minecraft-server-launcher/usr/share/minecraft-server-launcher/server.properties' + * const defaultServerPropertiesFile = Deno.openSync(DEFAULT_SERVER_PROPERTIES_PATH); + */ +writeFileAndDir(DEFAULT_SERVER_PROPERTIES_PATH, '#Minecraft server properties'); + +/** + * error: NotFound: No such file or directory (os error 2): readfile '/home//.development/minecraft-server-launcher/etc/minecraft-server-launcher/config.json' + * sysConf = Deno.readFileSync(SYS_CONFIG_FILE_PATH); + */ +writeFileAndDir(SYS_CONFIG_FILE_PATH, JSON.stringify(defaultConfig, undefined, 4)); + +//---------------------------------------------------------------------------------------------------------------------- +// setting tests config file + +const testConfig = { ...defaultConfig }; +testConfig.versionManifestV2Url = FAKE_SERVER_VERSION_MANIFEST_V2_URL; + +writeFileAndDir(USR_CONFIG_FILE_PATH, JSON.stringify(testConfig, undefined, 4)); diff --git a/scripts/utils.ts b/scripts/utils.ts new file mode 100644 index 0000000..ac1fb82 --- /dev/null +++ b/scripts/utils.ts @@ -0,0 +1,291 @@ +import { existsSync } from 'std/fs/exists.ts'; +import { WalkEntry, WalkOptions, walkSync } from 'std/fs/walk.ts'; +import { resolve } from 'std/path/resolve.ts'; + +export const PROJ_ROOT = resolve(new URL(import.meta.url).pathname, '..', '..'); +export const SRC_DIR = resolve(PROJ_ROOT, 'src'); +export const TESTS_DIR = resolve(PROJ_ROOT, 'tests'); +const TS_FILE_EXT_REX = /\.ts$/; +const SKIP_TEST_COMMENT_REX = /\/\/\s*@skip-test/gm; + +/* +import { getEmptyTsFiles, getSkipTestSrcFiles, getSrcFilesThatShouldHaveTestFile } from './utils.ts'; +const srcFilesWithoutTestFile = getSrcFilesThatShouldHaveTestFile(); +const emptyTsFiles = getEmptyTsFiles(); +const skipTestSrcFiles = getSkipTestSrcFiles(); + +let exitCode = 0; + +// check if there are src files with the @skip-test comment +if (skipTestSrcFiles.length > 0) { + for (const srcFile of skipTestSrcFiles) { + console.log(`%c[SKIP TEST] %c${srcFile}`, 'color: orange', 'color: yellow'); + } +} + +// check if there are src files WITHOUT TEST files +if (srcFilesWithoutTestFile.length > 0) { + for (const srcFile of srcFilesWithoutTestFile) { + console.log(`%c[WITHOUT TEST] %c${srcFile}`, 'color: red', 'color: yellow'); + } + exitCode = 1; +} + +// check if there are EMPTY TS FILES, in src or test +if (emptyTsFiles.length > 0) { + for (const tsFile of emptyTsFiles) { + console.log(`%c[EMPTY TS FILE] %c${tsFile}`, 'color: red', 'color: gray'); + } + exitCode = 1; +} + +if (exitCode === 0) { + console.log(`%c[CHECK PASS]`, 'color: green'); +} else { + Deno.exit(exitCode); +} + +*/ + +/** + + #!/usr/bin/env -S deno run -A +// script to generate an empty .test.ts file for each .ts file that doesnt have one +import { writeFileAndDir } from 'utils/fs.ts'; +import { getSkipTestSrcFiles, getSrcFilesThatShouldHaveTestFile, sourceFilePathToTestFilePath } from './utils.ts'; + +const skipTestSrcFiles = getSkipTestSrcFiles(); + +if (skipTestSrcFiles.length > 0) { + for (const srcFile of skipTestSrcFiles) { + console.log(`%c[SKIP TEST] %c${srcFile}`, 'color: orange', 'color: yellow'); + } +} + +for (const sourceFilePath of getSrcFilesThatShouldHaveTestFile()) { + const testFilePath = sourceFilePathToTestFilePath(sourceFilePath); + + console.log(`%c[GENERATE TEST] %c${testFilePath}`, 'color: green', 'color: yellow'); + writeFileAndDir(testFilePath, ''); +} + + */ + +/** +import './set_build_env.ts'; + +import { log } from 'iggs-utils'; +import { join, resolve } from 'std/path/mod.ts'; +import { defaultConfig } from 'utils/config.ts'; +import { copyFileRecursive, silentRemove, writeFileAndDir } from 'utils/fs.ts'; +import { logger } from 'utils/logger.ts'; +import { CONFIG_FILE_NAME, DEFAULT_SERVER_PROPERTIES_PATH, SYS_CONFIG_FILE_PATH } from 'utils/paths.ts'; +import { pkgInfo } from '../src/utils/package_info.ts'; +import { exe, LINUX_BIN_PATH } from './utils.ts'; +export async function mkDebPkg(): Promise { + exe('deno', ['compile', '--unstable', '--target=x86_64-unknown-linux-gnu', '-A', '--output=' + LINUX_BIN_PATH, './src/main.ts']); + + const controlFile: DebianControlFile = { + Package: pkgInfo.name, + Version: pkgInfo.version, + Architecture: 'amd64', + Maintainer: pkgInfo.maintainer, + Description: pkgInfo.description, + Homepage: pkgInfo.homepage, + }; + + const controlFileContent = Object.entries(controlFile) + .reduce((prev, [key, value]) => `${prev}${key}: ${value}\n`, ''); + + logger.debug(`creating debian package`, '\n', controlFileContent); + // generating deb package directories + const ASSETS_DIR = resolve('assets'); + const DEFAULT_CONFIG_FILE_PATH = resolve(ASSETS_DIR, 'defaults', CONFIG_FILE_NAME); + // const DEFAULT_DEFAULT_SERVER_PROPERTIES_PATH = resolve(ASSETS_DIR, 'defaults', 'server.properties'); + + const PKG_DIR = resolve('dist', 'deb_package'); + const PKG_ROOT = resolve(PKG_DIR, pkgInfo.name); + const PKG_BIN_PATH = join(PKG_ROOT, 'usr', 'bin', 'misela'); + const PKG_CONTROL_FILE_PATH = join(PKG_ROOT, 'DEBIAN', 'control'); + const PKG_DOC_PATH = join(PKG_ROOT, 'usr', 'share', 'doc', pkgInfo.name, 'README.md'); + const PKG_SYS_CONFIG_FILE_PATH = join(PKG_ROOT, SYS_CONFIG_FILE_PATH); + const PKG_DEFAULT_SERVER_PROPERTIES_PATH = join(PKG_ROOT, DEFAULT_SERVER_PROPERTIES_PATH); + + const DEB_PKG_PATH = resolve('dist', `${pkgInfo.name}_${pkgInfo.version}_linux_amd64.deb`); + + silentRemove(PKG_DIR, { recursive: true }); + writeFileAndDir(PKG_CONTROL_FILE_PATH, controlFileContent); + copyFileRecursive(LINUX_BIN_PATH, PKG_BIN_PATH); + copyFileRecursive('./README.md', PKG_DOC_PATH); + copyFileRecursive(DEFAULT_CONFIG_FILE_PATH, PKG_SYS_CONFIG_FILE_PATH); + writeFileAndDir(PKG_DEFAULT_SERVER_PROPERTIES_PATH, JSON.stringify(defaultConfig, null, 4)); + + logger.debug('creating', DEB_PKG_PATH); + await new Deno.Command('dpkg-deb', { + args: ['--build', PKG_ROOT, DEB_PKG_PATH], + stderr: 'inherit', + stdin: 'inherit', + stdout: 'inherit', + }).output(); + + logger.debug('successfully created deb package'); + + return DEB_PKG_PATH; +} + + * + */ + +/** + * import { log } from 'iggs-utils'; +import { logger } from 'utils/logger.ts'; +import { pkgInfo } from 'utils/package_info.ts'; +import { mkDebPkg } from './mk_deb_pkg_mod.ts'; +import { exe } from './utils.ts'; + * // lint +logger.info('linting...'); +exe('deno', ['lint']); + +// format +logger.info('formatting...'); +exe('deno', ['fmt']); + +// do code checks +logger.info('checking...'); +exe('./scripts/check.ts'); + +// run tests +logger.info('testing...'); +exe('deno', ['task', 'test']); + +// check if tag exists +logger.info(`checking if Tag ${pkgInfo.version} exists...`); +await checkIfTagExists(); + +// build deb package +logger.info('building deb package...'); +const LINUX_BIN_PATH = await mkDebPkg(); + +// commit changes +logger.info('committing changes...'); +exe('git', ['commit', '-m', `tag ${pkgInfo.version}`]); + +// tag the commit with the current version +logger.info(`tagging ${pkgInfo.version}...`); +exe('git', ['tag', pkgInfo.version]); + +// push the tag +logger.info('pushing tag...'); +exe('git', ['push', 'origin', pkgInfo.version]); + +//Upload deb backage as release assets +logger.info(`uploading ${LINUX_BIN_PATH} asset...`); +exe('gh', ['release', 'create', pkgInfo.version, LINUX_BIN_PATH]); + +async function checkIfTagExists() { + const tags: GhRelease[] = await fetch('https://api.github.com/repos/alexrr2iggs/minecraft_server_updater/releases').then((r) => r.json()); + const tagAlreadyExists = tags?.find((t: GhRelease) => t?.tag_name === pkgInfo.version); + if (tagAlreadyExists) { + console.warn(`Tag ${pkgInfo.version} already exists\nsee ${tagAlreadyExists.html_url}`); + Deno.exit(1); + } +} + + */ + +export function exe(command: string, ...args: string[]): Deno.CommandOutput { + const cmd = new Deno.Command(command, { + args, + stderr: 'inherit', + stdin: 'inherit', + stdout: 'inherit', + }); + const cmdOutput = cmd.outputSync(); + + if (cmdOutput.code !== 0) { + Deno.exit(cmdOutput.code); + } + return cmdOutput; +} + +export function getEmptyFiles(dir: string | URL, ...exts: string[]): string[] { + const walkOptions: WalkOptions = { + exts, + includeDirs: false, + }; + + const files: IterableIterator = walkSync(dir, walkOptions); + const emptyFiles: string[] = []; + + for (const tsFile of files) { + if (isEmptyFile(tsFile.path)) { + emptyFiles.push(tsFile.path); + } + } + + return emptyFiles; +} + +// export function getSkipTestSrcFiles(): string[] { +// const srcTsFiles = walkSync(SRC_DIR, { exts: ['ts'], includeDirs: false }); + +// const skipTestFiles: string[] = []; +// for (const srcTsFile of srcTsFiles) { +// const srcTxt = Deno.readTextFileSync(srcTsFile.path); +// if (srcTxt.match(SKIP_TEST_COMMENT_REX)) { +// skipTestFiles.push(srcTsFile.path); +// } +// } + +// return skipTestFiles; +// } + +/** + * returns an array of string paths with the source files with the @skip-test comment + * @returns + */ +export function getSkipTestSrcs(): string[] { + const srcFiles = walkSync(SRC_DIR, { includeDirs: false, exts: ['ts'] }); + const skipTestSrcs = []; + + for (const srcFile of srcFiles) { + if (!hasSkipTestComment(srcFile.path)) { + skipTestSrcs.push(srcFile.path); + } + } + return skipTestSrcs; +} + +export function getsMissingTestSrcs(): string[] { + const srcFiles = walkSync(SRC_DIR, { includeDirs: false, exts: ['ts'] }); + const missingTestSrcs = []; + + for (const srcFile of srcFiles) { + if (!hasTest(srcFile.path) && !hasSkipTestComment(srcFile.path)) { + missingTestSrcs.push(srcFile.path); + } + } + + return missingTestSrcs; +} + +export function hasTest(srcTsFile: string): boolean { + return existsSync(sourceFilePathToTestFilePath(srcTsFile)); +} + +/** + * check if the src file has the @skip-test comment. + * @param srcTsFile + * @returns boolean + */ +export function hasSkipTestComment(srcTsFile: string): boolean { + return !!Deno.readTextFileSync(srcTsFile).match(SKIP_TEST_COMMENT_REX); +} + +export function sourceFilePathToTestFilePath(srcFile: string): string { + return resolve(srcFile).replace(SRC_DIR, TESTS_DIR).replace(TS_FILE_EXT_REX, '.test.ts'); +} + +export function isEmptyFile(path: string): boolean { + return Deno.statSync(path).size === 0; +} diff --git a/src/errors/invalid_semver.ts b/src/errors/invalid_semver.ts index d8c6bad..979b379 100644 --- a/src/errors/invalid_semver.ts +++ b/src/errors/invalid_semver.ts @@ -1,3 +1,4 @@ +//@skip-test export class InvalidSemver extends Error { constructor(version: string) { super(`Invalid semver ${version}`); diff --git a/src/errors/mc_server_download_failed.ts b/src/errors/mc_server_download_failed.ts index d865a91..843bb58 100644 --- a/src/errors/mc_server_download_failed.ts +++ b/src/errors/mc_server_download_failed.ts @@ -1,3 +1,4 @@ +//@skip-test export class MinecraftServerDownloadError extends Error { constructor(response: Response) { super(`Failed to download minecraft server: url ${response.url}, status:${response.statusText}, status code: ${response.status} `); diff --git a/src/errors/mc_version_not_found.ts b/src/errors/mc_version_not_found.ts index d0cb73b..1f07099 100644 --- a/src/errors/mc_version_not_found.ts +++ b/src/errors/mc_version_not_found.ts @@ -1,3 +1,4 @@ +//@skip-test export class VersionNotFoundManifestV2 extends Error { constructor(version: string) { super(`Minecraft version ${version} not found`); diff --git a/src/types/conf.ts b/src/types/conf.ts index cc61313..ffad1a3 100644 --- a/src/types/conf.ts +++ b/src/types/conf.ts @@ -1,3 +1,4 @@ +//@skip-test export interface MinecraftServerLauncherConf { serverInstallationDir?: string; versionManifestV2Url?: string; diff --git a/src/types/packages.ts b/src/types/packages.ts index 0a3fb2d..bbd38bf 100644 --- a/src/types/packages.ts +++ b/src/types/packages.ts @@ -1,3 +1,4 @@ +//@skip-test export interface Packages { arguments?: Arguments; assetIndex?: AssetIndex; diff --git a/src/types/version_manifest_v2.ts b/src/types/version_manifest_v2.ts index 7568328..dc0bb9a 100644 --- a/src/types/version_manifest_v2.ts +++ b/src/types/version_manifest_v2.ts @@ -1,3 +1,4 @@ +//@skip-test export interface VersionManifestV2 { latest: Latest; versions: Version[];