diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ddeab697..4122c1c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,9 @@ jobs: - name: Install dependencies run: pnpm install + - name: Run global tests + run: pnpm test + - name: Run tests run: pnpm -r lint diff --git a/apps/__tests__/apps.test.ts b/apps/__tests__/apps.test.ts new file mode 100644 index 00000000..5a26e48b --- /dev/null +++ b/apps/__tests__/apps.test.ts @@ -0,0 +1,146 @@ +import fs from "fs"; +import jsyaml from "js-yaml"; + +interface AppConfig { + id: string; + port: number; + requirements?: { + ports?: number[]; + }; + name: string; + description: string; + version: string; + image: string; + short_desc: string; + author: string; + source: string; + available: boolean; +} + +const networkExceptions = ["pihole", "tailscale"]; +const getAppConfigs = (): AppConfig[] => { + const apps: AppConfig[] = []; + + const appsDir = fs.readdirSync("./apps"); + + appsDir.forEach((app) => { + const path = `./apps/${app}/config.json`; + + if (fs.existsSync(path)) { + const configFile = fs.readFileSync(path).toString(); + const config: AppConfig = JSON.parse(configFile); + + if (config.available) { + apps.push(config); + } + } + }); + + return apps; +}; + +describe("App configs", () => { + it("Get app config should return at least one app", () => { + const apps = getAppConfigs(); + + expect(apps.length).toBeGreaterThan(0); + }); + + it("Each app should have an id", () => { + const apps = getAppConfigs(); + + apps.forEach((app) => { + expect(app.id).toBeDefined(); + }); + }); + + it("Each app should have a name", () => { + const apps = getAppConfigs(); + + apps.forEach((app) => { + expect(app.name).toBeDefined(); + }); + }); + + it("Each app should have a description", () => { + const apps = getAppConfigs(); + + apps.forEach((app) => { + expect(app.description).toBeDefined(); + }); + }); + + it("Each app should have a port", () => { + const apps = getAppConfigs(); + + apps.forEach((app) => { + expect(app.port).toBeDefined(); + expect(app.port).toBeGreaterThan(999); + expect(app.port).toBeLessThan(65535); + }); + }); + + it("Each app should have a different port", () => { + const appConfigs = getAppConfigs(); + const ports = appConfigs.map((app) => app.port); + expect(new Set(ports).size).toBe(appConfigs.length); + }); + + it("Each app should have a unique id", () => { + const appConfigs = getAppConfigs(); + const ids = appConfigs.map((app) => app.id); + expect(new Set(ids).size).toBe(appConfigs.length); + }); + + it("Each app should have a docker-compose file beside it", () => { + const apps = getAppConfigs(); + + apps.forEach((app) => { + expect(fs.existsSync(`./apps/${app.id}/docker-compose.yml`)).toBe(true); + }); + }); + + it("Each app should have a container name equals to its id", () => { + const apps = getAppConfigs(); + + apps.forEach((app) => { + const dockerComposeFile = fs + .readFileSync(`./apps/${app.id}/docker-compose.yml`) + .toString(); + + const dockerCompose: any = jsyaml.load(dockerComposeFile); + + if (!dockerCompose.services[app.id]) { + console.error(app.id); + } + + expect(dockerCompose.services[app.id]).toBeDefined(); + expect(dockerCompose.services[app.id].container_name).toBe(app.id); + }); + }); + + it("Each app should have network tipi_main_network", () => { + const apps = getAppConfigs(); + + apps.forEach((app) => { + if (!networkExceptions.includes(app.id)) { + const dockerComposeFile = fs + .readFileSync(`./apps/${app.id}/docker-compose.yml`) + .toString(); + + const dockerCompose: any = jsyaml.load(dockerComposeFile); + + expect(dockerCompose.services[app.id]).toBeDefined(); + + if (!dockerCompose.services[app.id].networks) { + console.error(app.id); + } + + expect(dockerCompose.services[app.id].networks).toBeDefined(); + expect(dockerCompose.services[app.id].networks).toStrictEqual([ + "tipi_main_network", + ]); + } + }); + }); +}); diff --git a/apps/adguard/docker-compose.yml b/apps/adguard/docker-compose.yml index 1953149c..9be29925 100644 --- a/apps/adguard/docker-compose.yml +++ b/apps/adguard/docker-compose.yml @@ -1,7 +1,7 @@ version: "3.7" services: - adguardhome: + adguard: image: adguard/adguardhome:v0.107.6 container_name: adguard volumes: diff --git a/apps/invidious/docker-compose.arm.yml b/apps/invidious/docker-compose.arm.yml index e83042dd..e47850c9 100644 --- a/apps/invidious/docker-compose.arm.yml +++ b/apps/invidious/docker-compose.arm.yml @@ -25,6 +25,8 @@ services: retries: 2 depends_on: - invidious-db + networks: + - tipi_main_network invidious-db: user: 1000:1000 diff --git a/apps/invidious/docker-compose.yml b/apps/invidious/docker-compose.yml index fae8d63d..38ec9953 100644 --- a/apps/invidious/docker-compose.yml +++ b/apps/invidious/docker-compose.yml @@ -26,6 +26,8 @@ services: retries: 2 depends_on: - invidious-db + networks: + - tipi_main_network invidious-db: user: 1000:1000 diff --git a/apps/prowlarr/docker-compose.yml b/apps/prowlarr/docker-compose.yml index 4885600e..629babec 100644 --- a/apps/prowlarr/docker-compose.yml +++ b/apps/prowlarr/docker-compose.yml @@ -5,7 +5,8 @@ services: image: ghcr.io/linuxserver/prowlarr:develop environment: - TZ=${TZ} # Can use any env variable. List in runtipi/templates/env-sample - - DNS_IP=${DNS_IP} + dns: + - ${DNS_IP} volumes: - ${APP_DATA_DIR}/data/config:/config #Always start the path with ${APP_DATA_DIR}. This will put all data inside app-data/my-app/data ports: diff --git a/apps/sonarr/docker-compose.yml b/apps/sonarr/docker-compose.yml index 785da965..bb54ee57 100644 --- a/apps/sonarr/docker-compose.yml +++ b/apps/sonarr/docker-compose.yml @@ -1,6 +1,6 @@ version: "3.7" services: - radarr: + sonarr: image: lscr.io/linuxserver/sonarr container_name: sonarr environment: diff --git a/apps/transmission/docker-compose.yml b/apps/transmission/docker-compose.yml index d49c0cf4..35ee6053 100644 --- a/apps/transmission/docker-compose.yml +++ b/apps/transmission/docker-compose.yml @@ -3,6 +3,8 @@ services: transmission: image: lscr.io/linuxserver/transmission container_name: transmission + dns: + - ${DNS_IP} environment: - PUID=1000 - PGID=1000 @@ -16,7 +18,6 @@ services: volumes: - ${APP_DATA_DIR}/data/config:/config - ${ROOT_FOLDER_HOST}/media/torrents:/downloads - - ${ROOT_FOLDER_HOST}/media/torrents/watch:/watch ports: - ${APP_PORT}:9091 - 51413:51413 diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..be5267d2 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,7 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + testMatch: ["**/__tests__/**/*.test.ts"], + testPathIgnorePatterns: ["/node_modules/", "/packages/"], +}; diff --git a/package.json b/package.json index 6c725249..36e3c3f8 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.2.0", "description": "A homeserver for everyone", "scripts": { + "test": "jest", "prepare": "husky install", "act:test-install": "act --container-architecture linux/amd64 -j test-install", "act:docker": "act --container-architecture linux/amd64 --secret-file github.secrets -j docker", @@ -10,9 +11,15 @@ "start:rc": "docker-compose -f docker-compose.rc.yml --env-file .env up --build", "start:prod": "docker-compose --env-file .env up --build" }, - "dependencies": {}, "devDependencies": { - "husky": "^8.0.1" + "@types/jest": "^27.5.0", + "@types/js-yaml": "^4.0.5", + "@types/node": "17.0.31", + "husky": "^8.0.1", + "jest": "^28.1.0", + "js-yaml": "^4.1.0", + "ts-jest": "^28.0.2", + "typescript": "4.6.4" }, "repository": { "type": "git", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index efda02b2..f26d6314 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,9 +4,23 @@ importers: .: specifiers: + '@types/jest': ^27.5.0 + '@types/js-yaml': ^4.0.5 + '@types/node': 17.0.31 husky: ^8.0.1 + jest: ^28.1.0 + js-yaml: ^4.1.0 + ts-jest: ^28.0.2 + typescript: 4.6.4 devDependencies: + '@types/jest': 27.5.0 + '@types/js-yaml': 4.0.5 + '@types/node': 17.0.31 husky: 8.0.1 + jest: 28.1.0_@types+node@17.0.31 + js-yaml: 4.1.0 + ts-jest: 28.0.2_z3fx76c5ksuwr36so7o5uc2kcy + typescript: 4.6.4 packages/dashboard: specifiers: @@ -78,7 +92,7 @@ importers: eslint: 8.12.0 eslint-config-airbnb-typescript: 17.0.0_r46exuh3jlhq2wmrnqx2ufqspa eslint-config-next: 12.1.4_e6a2zi6fqdwfehht5cxvkmo3zu - eslint-plugin-import: 2.26.0_eslint@8.12.0 + eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy postcss: 8.4.13 tailwindcss: 3.0.24 typescript: 4.6.4 @@ -171,7 +185,7 @@ importers: eslint: 8.15.0 eslint-config-airbnb-typescript: 17.0.0_c2ouaf3l4ivgkc6ae4nebvztom eslint-config-prettier: 8.5.0_eslint@8.15.0 - eslint-plugin-import: 2.26.0_eslint@8.15.0 + eslint-plugin-import: 2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy eslint-plugin-prettier: 4.0.0_iqftbjqlxzn3ny5nablrkczhqi jest: 28.1.0 nodemon: 2.0.16 @@ -2104,6 +2118,10 @@ packages: resolution: {integrity: sha512-6+0ekgfusHftJNYpihfkMu8BWdeHs9EOJuGcSofErjstGPfPGEu9yTu4t460lTzzAMl2cM5zngQJqPMHbbnvYA==} dev: true + /@types/js-yaml/4.0.5: + resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==} + dev: true + /@types/json-buffer/3.0.0: resolution: {integrity: sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==} dev: false @@ -3299,6 +3317,11 @@ packages: /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.0.0 @@ -3826,7 +3849,7 @@ packages: dependencies: confusing-browser-globals: 1.0.11 eslint: 8.15.0 - eslint-plugin-import: 2.26.0_eslint@8.15.0 + eslint-plugin-import: 2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy object.assign: 4.1.2 object.entries: 1.1.5 semver: 6.3.0 @@ -3841,7 +3864,7 @@ packages: dependencies: confusing-browser-globals: 1.0.11 eslint: 8.12.0 - eslint-plugin-import: 2.26.0_eslint@8.12.0 + eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy object.assign: 4.1.2 object.entries: 1.1.5 semver: 6.3.0 @@ -3859,7 +3882,7 @@ packages: '@typescript-eslint/parser': 5.22.0_hcfsmds2fshutdssjqluwm76uu eslint: 8.15.0 eslint-config-airbnb-base: 15.0.0_gwd37gqv3vjv3xlpl7ju3ag2qu - eslint-plugin-import: 2.26.0_eslint@8.15.0 + eslint-plugin-import: 2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy dev: true /eslint-config-airbnb-typescript/17.0.0_r46exuh3jlhq2wmrnqx2ufqspa: @@ -3874,7 +3897,7 @@ packages: '@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede eslint: 8.12.0 eslint-config-airbnb-base: 15.0.0_m4t3vvrby3btqwe437vnsnvyim - eslint-plugin-import: 2.26.0_eslint@8.12.0 + eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy dev: true /eslint-config-next/12.1.4_e6a2zi6fqdwfehht5cxvkmo3zu: @@ -3893,13 +3916,14 @@ packages: eslint: 8.12.0 eslint-import-resolver-node: 0.3.4 eslint-import-resolver-typescript: 2.4.0_l3k33lf43msdtqtpwrwceacqke - eslint-plugin-import: 2.25.2_eslint@8.12.0 + eslint-plugin-import: 2.25.2_svocbphju65ulgskrkawser2je eslint-plugin-jsx-a11y: 6.5.1_eslint@8.12.0 eslint-plugin-react: 7.29.1_eslint@8.12.0 eslint-plugin-react-hooks: 4.3.0_eslint@8.12.0 next: 12.1.6_talmm3uuvp6ssixt2qevhfgvue typescript: 4.6.4 transitivePeerDependencies: + - eslint-import-resolver-webpack - supports-color dev: true @@ -3935,7 +3959,7 @@ packages: dependencies: debug: 4.3.4 eslint: 8.12.0 - eslint-plugin-import: 2.25.2_eslint@8.12.0 + eslint-plugin-import: 2.25.2_svocbphju65ulgskrkawser2je glob: 7.2.0 is-glob: 4.0.3 resolve: 1.22.0 @@ -3944,27 +3968,69 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.3: + /eslint-module-utils/2.7.3_sysdrzuw2ki4kxpuwc4tznw2ha: resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==} engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true dependencies: - debug: 3.2.7 - find-up: 2.1.0 + '@typescript-eslint/parser': 5.10.1_uhoeudlwl7kc47h4kncsfowede + eslint-import-resolver-node: 0.3.6 + eslint-import-resolver-typescript: 2.4.0_l3k33lf43msdtqtpwrwceacqke dev: true - /eslint-plugin-import/2.25.2_eslint@8.12.0: + /eslint-module-utils/2.7.3_wex3ustmkv4ospy3s77r6ihlwq: + resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede + eslint-import-resolver-node: 0.3.6 + dev: true + + /eslint-plugin-import/2.25.2_svocbphju65ulgskrkawser2je: resolution: {integrity: sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==} engines: {node: '>=4'} peerDependencies: + '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true dependencies: + '@typescript-eslint/parser': 5.10.1_uhoeudlwl7kc47h4kncsfowede array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.12.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.3 + eslint-module-utils: 2.7.3_sysdrzuw2ki4kxpuwc4tznw2ha has: 1.0.3 is-core-module: 2.9.0 is-glob: 4.0.3 @@ -3972,43 +4038,30 @@ packages: object.values: 1.1.5 resolve: 1.22.0 tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color dev: true - /eslint-plugin-import/2.26.0_eslint@8.12.0: - resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - dependencies: - array-includes: 3.1.5 - array.prototype.flat: 1.3.0 - debug: 2.6.9 - doctrine: 2.1.0 - eslint: 8.12.0 - eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.3 - has: 1.0.3 - is-core-module: 2.9.0 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.values: 1.1.5 - resolve: 1.22.0 - tsconfig-paths: 3.14.1 - dev: true - - /eslint-plugin-import/2.26.0_eslint@8.15.0: + /eslint-plugin-import/2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: + '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true dependencies: + '@typescript-eslint/parser': 5.22.0_hcfsmds2fshutdssjqluwm76uu array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.15.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.3 + eslint-module-utils: 2.7.3_wex3ustmkv4ospy3s77r6ihlwq has: 1.0.3 is-core-module: 2.9.0 is-glob: 4.0.3 @@ -4016,6 +4069,41 @@ packages: object.values: 1.1.5 resolve: 1.22.0 tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-import/2.26.0_hhyjdrupy4c2vgtpytri6cjwoy: + resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede + array-includes: 3.1.5 + array.prototype.flat: 1.3.0 + debug: 2.6.9 + doctrine: 2.1.0 + eslint: 8.12.0 + eslint-import-resolver-node: 0.3.6 + eslint-module-utils: 2.7.3_wex3ustmkv4ospy3s77r6ihlwq + has: 1.0.3 + is-core-module: 2.9.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.values: 1.1.5 + resolve: 1.22.0 + tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color dev: true /eslint-plugin-jsx-a11y/6.5.1_eslint@8.12.0: @@ -4422,13 +4510,6 @@ packages: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} dev: false - /find-up/2.1.0: - resolution: {integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=} - engines: {node: '>=4'} - dependencies: - locate-path: 2.0.0 - dev: true - /find-up/4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -5226,6 +5307,34 @@ packages: - ts-node dev: true + /jest-cli/28.1.0_@types+node@17.0.31: + resolution: {integrity: sha512-fDJRt6WPRriHrBsvvgb93OxgajHHsJbk4jZxiPqmZbMDRcHskfJBBfTyjFko0jjfprP544hOktdSi9HVgl4VUQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 28.1.0 + '@jest/test-result': 28.1.0 + '@jest/types': 28.1.0 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.10 + import-local: 3.1.0 + jest-config: 28.1.0_@types+node@17.0.31 + jest-util: 28.1.0 + jest-validate: 28.1.0 + prompts: 2.4.2 + yargs: 17.4.1 + transitivePeerDependencies: + - '@types/node' + - supports-color + - ts-node + dev: true + /jest-config/28.1.0: resolution: {integrity: sha512-aOV80E9LeWrmflp7hfZNn/zGA4QKv/xsn2w8QCBP0t0+YqObuCWTSgNbHJ0j9YsTuCO08ZR/wsvlxqqHX20iUA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -5631,6 +5740,25 @@ packages: - ts-node dev: true + /jest/28.1.0_@types+node@17.0.31: + resolution: {integrity: sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 28.1.0 + import-local: 3.1.0 + jest-cli: 28.1.0_@types+node@17.0.31 + transitivePeerDependencies: + - '@types/node' + - supports-color + - ts-node + dev: true + /js-cookie/3.0.1: resolution: {integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==} engines: {node: '>=12'} @@ -5787,14 +5915,6 @@ packages: /lines-and-columns/1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - /locate-path/2.0.0: - resolution: {integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=} - engines: {node: '>=4'} - dependencies: - p-locate: 2.0.0 - path-exists: 3.0.0 - dev: true - /locate-path/5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -6289,13 +6409,6 @@ packages: engines: {node: '>=8.0.0'} dev: false - /p-limit/1.3.0: - resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} - engines: {node: '>=4'} - dependencies: - p-try: 1.0.0 - dev: true - /p-limit/2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -6303,13 +6416,6 @@ packages: p-try: 2.2.0 dev: true - /p-locate/2.0.0: - resolution: {integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=} - engines: {node: '>=4'} - dependencies: - p-limit: 1.3.0 - dev: true - /p-locate/4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -6324,11 +6430,6 @@ packages: p-finally: 1.0.0 dev: false - /p-try/1.0.0: - resolution: {integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=} - engines: {node: '>=4'} - dev: true - /p-try/2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -6391,11 +6492,6 @@ packages: pause: 0.0.1 dev: false - /path-exists/3.0.0: - resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=} - engines: {node: '>=4'} - dev: true - /path-exists/4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -7374,6 +7470,40 @@ packages: yargs-parser: 20.2.9 dev: true + /ts-jest/28.0.2_z3fx76c5ksuwr36so7o5uc2kcy: + resolution: {integrity: sha512-IOZMb3D0gx6IHO9ywPgiQxJ3Zl4ECylEFwoVpENB55aTn5sdO0Ptyx/7noNBxAaUff708RqQL4XBNxxOVjY0vQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@types/jest': ^27.0.0 + babel-jest: ^28.0.0 + esbuild: '*' + jest: ^28.0.0 + typescript: '>=4.3' + peerDependenciesMeta: + '@babel/core': + optional: true + '@types/jest': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + dependencies: + '@types/jest': 27.5.0 + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 28.1.0_@types+node@17.0.31 + jest-util: 28.1.0 + json5: 2.2.1 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.3.7 + typescript: 4.6.4 + yargs-parser: 20.2.9 + dev: true + /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: diff --git a/scripts/configure.sh b/scripts/configure.sh index 4c58a95c..d5d7a4db 100755 --- a/scripts/configure.sh +++ b/scripts/configure.sh @@ -14,39 +14,10 @@ echo "=============== TIPI =================" echo "======================================" echo -sudo apt-get update -sudo apt-get install -y jq coreutils ca-certificates curl gnupg lsb-release - -LSB="$(lsb_release -is)" - -# Add docker gpg key (Debian) -if [[ "${LSB}" == "Debian" ]]; then - curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg -fi - -# Add docker gpg key (Ubuntu) -if [[ "${LSB}" == "Ubuntu" ]]; then - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg -fi - -# Add deb repo for docker (Debian) -if [[ "${LSB}" == "Debian" ]]; then - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null -fi - -# Add deb repo for docker (Ubuntu) -if [[ "${LSB}" == "Ubuntu" ]]; then - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null -fi - -sudo apt-get update -sudo apt-get install -y docker-ce docker-ce-cli containerd.io - -# Install docker compose if not here -if ! command -v docker-compose >/dev/null; then - sudo curl -L "https://github.com/docker/compose/releases/download/v2.3.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - sudo chmod +x /usr/local/bin/docker-compose -fi +sudo wget -O /usr/local/bin/pacapt https://github.com/icy/pacapt/raw/ng/pacapt +sudo chmod 755 /usr/local/bin/pacapt +sudo ln -sv /usr/local/bin/pacapt /usr/local/bin/pacman || true +sudo pacapt -Sy; sudo pacapt -S docker docker-ce docker-compose containerd.io jq coreutils curl -y # Create configured status touch "${ROOT_FOLDER}/state/configured" diff --git a/scripts/start.sh b/scripts/start.sh index d47f9077..fe3fe34d 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -98,8 +98,6 @@ function derive_entropy() { printf "%s" "${identifier}" | openssl dgst -sha256 -hmac "${tipi_seed}" | sed 's/^.* //' } -PUID="$(id -u)" -PGID="$(id -g)" TZ="$(cat /etc/timezone | sed 's/\//\\\//g' || echo "Europe/Berlin")" # Copy the app state if it isn't here @@ -120,11 +118,6 @@ fi # Get dns ip if pihole is installed str=$(get_json_field ${STATE_FOLDER}/apps.json installed) -# if pihole is present in str add it as DNS -# if [[ $str = *"pihole"* ]]; then -# DNS_IP=10.21.21.201 -# fi - # Create seed file with cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 if [[ ! -f "${STATE_FOLDER}/seed" ]]; then echo "Generating seed..." @@ -150,8 +143,6 @@ JWT_SECRET=$(derive_entropy "jwt") for template in "${ENV_FILE}"; do sed -i "s//${DNS_IP}/g" "${template}" sed -i "s//${INTERNAL_IP}/g" "${template}" - sed -i "s//${PUID}/g" "${template}" - sed -i "s//${PGID}/g" "${template}" sed -i "s//${TZ}/g" "${template}" sed -i "s//${JWT_SECRET}/g" "${template}" sed -i "s//${SED_ROOT_FOLDER}/g" "${template}" @@ -167,6 +158,9 @@ mv -f "$ENV_FILE" "$ROOT_FOLDER/.env" echo "Running system-info.sh..." bash "${ROOT_FOLDER}/scripts/system-info.sh" +# Add crontab to run system-info.sh every minute +! (crontab -l | grep -q "${ROOT_FOLDER}/scripts/system-info.sh") && (crontab -l; echo "* * * * * ${ROOT_FOLDER}/scripts/system-info.sh") | crontab - + ## Don't run if config-only if [[ ! $ci == "true" ]]; then diff --git a/templates/env-sample b/templates/env-sample index 4aa5e58c..f9c2ba1d 100644 --- a/templates/env-sample +++ b/templates/env-sample @@ -2,8 +2,6 @@ # It will be overwritten on update. TZ= -PUID= -PGID= INTERNAL_IP= DNS_IP= ARCHITECTURE= diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..650222c3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es6", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "commonjs", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": false, + "jsx": "preserve", + "incremental": true + }, + "include": ["apps/**/*.ts"] +}