Merge pull request #241 from meienberger/release/0.7.1

Release/0.7.1
This commit is contained in:
Nicolas Meienberger 2022-10-19 21:18:58 +02:00 committed by GitHub
commit 83180709b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 290 additions and 96 deletions

View file

@ -5,5 +5,8 @@
node_modules
.next
dist/
**/dist/
**/next/
# all docker-compose files
docker-compose*.yml
Dockerfile*
.dockerignore

View file

@ -1,4 +1,4 @@
FROM node:18 AS build
FROM node:18 AS builder
RUN npm install node-gyp -g
@ -35,13 +35,13 @@ WORKDIR /api
COPY ./packages/system-api/package*.json /api/
RUN npm install --omit=dev
COPY --from=builder /api/dist /api/dist
WORKDIR /dashboard
COPY ./packages/dashboard/package*.json /dashboard/
RUN npm install --omit=dev
COPY --from=build /api/dist /api/dist
COPY --from=build /dashboard/.next /dashboard/.next
COPY ./packages/dashboard /dashboard
COPY --from=builder /dashboard/next.config.js ./
COPY --from=builder /dashboard/public ./public
COPY --from=builder /dashboard/package.json ./package.json
COPY --from=builder --chown=node:node /dashboard/.next/standalone ./
COPY --from=builder --chown=node:node /dashboard/.next/static ./.next/static
WORKDIR /

View file

@ -71,6 +71,7 @@ services:
APPS_REPO_ID: ${APPS_REPO_ID}
APPS_REPO_URL: ${APPS_REPO_URL}
DOMAIN: ${DOMAIN}
ARCHITECTURE: ${ARCHITECTURE}
networks:
- tipi_main_network
labels:

View file

@ -63,6 +63,7 @@ services:
APPS_REPO_ID: ${APPS_REPO_ID}
APPS_REPO_URL: ${APPS_REPO_URL}
DOMAIN: ${DOMAIN}
ARCHITECTURE: ${ARCHITECTURE}
networks:
- tipi_main_network
labels:
@ -85,7 +86,7 @@ services:
dashboard:
image: meienberger/runtipi:rc-${TIPI_VERSION}
command: /bin/sh -c "cd /dashboard && npm run start"
command: /bin/sh -c "cd /dashboard && node server.js"
container_name: dashboard
networks:
- tipi_main_network

View file

@ -63,6 +63,7 @@ services:
APPS_REPO_ID: ${APPS_REPO_ID}
APPS_REPO_URL: ${APPS_REPO_URL}
DOMAIN: ${DOMAIN}
ARCHITECTURE: ${ARCHITECTURE}
networks:
- tipi_main_network
labels:
@ -85,7 +86,7 @@ services:
dashboard:
image: meienberger/runtipi:${TIPI_VERSION}
command: /bin/sh -c "cd /dashboard && npm run start"
command: /bin/sh -c "cd /dashboard && node server.js"
restart: unless-stopped
container_name: dashboard
networks:

View file

@ -1,6 +1,6 @@
{
"name": "runtipi",
"version": "0.7.0",
"version": "0.7.1",
"description": "A homeserver for everyone",
"scripts": {
"prepare": "husky install",

View file

@ -1,7 +1,6 @@
/** @type {import('next').NextConfig} */
const { INTERNAL_IP, DOMAIN, NGINX_PORT } = process.env;
const nextConfig = {
output: 'standalone',
webpackDevMiddleware: (config) => {
config.watchOptions = {
poll: 1000,

View file

@ -1,6 +1,6 @@
{
"name": "dashboard",
"version": "0.7.0",
"version": "0.7.1",
"private": true,
"scripts": {
"test": "jest --colors",
@ -22,7 +22,7 @@
"framer-motion": "^6",
"graphql": "^15.8.0",
"graphql-tag": "^2.12.6",
"next": "12.1.6",
"next": "12.3.1",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-final-form": "^6.5.9",

View file

@ -1,6 +1,6 @@
{
"name": "system-api",
"version": "0.7.0",
"version": "0.7.1",
"description": "",
"exports": "./dist/server.js",
"type": "module",

View file

@ -2,6 +2,7 @@ import { z } from 'zod';
import * as dotenv from 'dotenv';
import fs from 'fs-extra';
import { readJsonFile } from '../../modules/fs/fs.helpers';
import { AppSupportedArchitecturesEnum } from '../../modules/apps/apps.types';
if (process.env.NODE_ENV !== 'production') {
dotenv.config({ path: '.env.dev' });
@ -21,11 +22,13 @@ const {
APPS_REPO_URL = '',
DOMAIN = '',
STORAGE_PATH = '/runtipi',
ARCHITECTURE = 'amd64',
} = process.env;
const configSchema = z.object({
NODE_ENV: z.union([z.literal('development'), z.literal('production'), z.literal('test')]),
status: z.union([z.literal('RUNNING'), z.literal('UPDATING'), z.literal('RESTARTING')]),
architecture: z.nativeEnum(AppSupportedArchitecturesEnum),
logs: z.object({
LOGS_FOLDER: z.string(),
LOGS_APP: z.string(),
@ -56,6 +59,7 @@ class Config {
LOGS_ERROR,
},
NODE_ENV: NODE_ENV as z.infer<typeof configSchema>['NODE_ENV'],
architecture: ARCHITECTURE as z.infer<typeof configSchema>['architecture'],
rootFolder: '/runtipi',
internalIp: INTERNAL_IP,
version: TIPI_VERSION,

View file

@ -1,5 +1,5 @@
import { faker } from '@faker-js/faker';
import { AppCategoriesEnum, AppInfo, AppStatusEnum, FieldTypes } from '../apps.types';
import { AppCategoriesEnum, AppInfo, AppStatusEnum, AppSupportedArchitecturesEnum, FieldTypes } from '../apps.types';
import App from '../app.entity';
interface IProps {
@ -10,10 +10,11 @@ interface IProps {
exposed?: boolean;
domain?: string;
exposable?: boolean;
supportedArchitectures?: AppSupportedArchitecturesEnum[];
}
const createApp = async (props: IProps) => {
const { installed = false, status = AppStatusEnum.RUNNING, requiredPort, randomField = false, exposed = false, domain = '', exposable = false } = props;
const { installed = false, status = AppStatusEnum.RUNNING, requiredPort, randomField = false, exposed = false, domain = '', exposable = false, supportedArchitectures } = props;
const categories = Object.values(AppCategoriesEnum);
@ -29,6 +30,7 @@ const createApp = async (props: IProps) => {
env_variable: 'TEST_FIELD',
},
],
name: faker.random.word(),
description: faker.random.words(),
tipi_version: faker.datatype.number({ min: 1, max: 10 }),
@ -37,6 +39,7 @@ const createApp = async (props: IProps) => {
source: faker.internet.url(),
categories: [categories[faker.datatype.number({ min: 0, max: categories.length - 1 })]],
exposable,
supported_architectures: supportedArchitectures,
};
if (randomField) {

View file

@ -1,12 +1,13 @@
import AppsService from '../apps.service';
import fs from 'fs-extra';
import { AppInfo, AppStatusEnum } from '../apps.types';
import { AppInfo, AppStatusEnum, AppSupportedArchitecturesEnum } from '../apps.types';
import App from '../app.entity';
import { createApp } from './apps.factory';
import { setupConnection, teardownConnection } from '../../../test/connection';
import { DataSource } from 'typeorm';
import { getEnvMap } from '../apps.helpers';
import EventDispatcher, { eventDispatcher, EventTypes } from '../../../core/config/EventDispatcher';
import { setConfig } from '../../../core/config/TipiConfig';
jest.mock('fs-extra');
jest.mock('child_process');
@ -152,6 +153,38 @@ describe('Install app', () => {
await expect(AppsService.installApp(app3.appInfo.id, { TEST_FIELD: 'test' }, true, 'test.com')).rejects.toThrowError(`Domain test.com already in use by app ${app2.appInfo.id}`);
});
it('Should throw if architecure is not supported', async () => {
const { MockFiles, appInfo } = await createApp({ supportedArchitectures: [AppSupportedArchitecturesEnum.ARM] });
// @ts-ignore
fs.__createMockFiles(MockFiles);
await expect(AppsService.installApp(appInfo.id, { TEST_FIELD: 'test' })).rejects.toThrowError(`App ${appInfo.id} is not supported on this architecture`);
});
it('Can install if architecture is supported', async () => {
setConfig('architecture', AppSupportedArchitecturesEnum.ARM);
const { MockFiles, appInfo } = await createApp({ supportedArchitectures: [AppSupportedArchitecturesEnum.ARM, AppSupportedArchitecturesEnum.ARM64] });
// @ts-ignore
fs.__createMockFiles(MockFiles);
await AppsService.installApp(appInfo.id, { TEST_FIELD: 'test' });
const app = await App.findOne({ where: { id: appInfo.id } });
expect(app).toBeDefined();
});
it('Can install if no architecture is specified', async () => {
setConfig('architecture', AppSupportedArchitecturesEnum.ARM);
const { MockFiles, appInfo } = await createApp({ supportedArchitectures: undefined });
// @ts-ignore
fs.__createMockFiles(MockFiles);
await AppsService.installApp(appInfo.id, { TEST_FIELD: 'test' });
const app = await App.findOne({ where: { id: appInfo.id } });
expect(app).toBeDefined();
});
});
describe('Uninstall app', () => {
@ -431,6 +464,50 @@ describe('List apps', () => {
expect(apps[1].id).toBe(sortedApps[1].id);
expect(apps[0].description).toBe('md desc');
});
it('Should not list apps that have supportedArchitectures and are not supported', async () => {
// Arrange
setConfig('architecture', AppSupportedArchitecturesEnum.ARM64);
const app3 = await createApp({ supportedArchitectures: [AppSupportedArchitecturesEnum.ARM] });
// @ts-ignore
fs.__createMockFiles(Object.assign(app3.MockFiles));
// Act
const { apps } = await AppsService.listApps();
// Assert
expect(apps).toBeDefined();
expect(apps.length).toBe(0);
});
it('Should list apps that have supportedArchitectures and are supported', async () => {
// Arrange
setConfig('architecture', AppSupportedArchitecturesEnum.ARM);
const app3 = await createApp({ supportedArchitectures: [AppSupportedArchitecturesEnum.ARM] });
// @ts-ignore
fs.__createMockFiles(Object.assign(app3.MockFiles));
// Act
const { apps } = await AppsService.listApps();
// Assert
expect(apps).toBeDefined();
expect(apps.length).toBe(1);
});
it('Should list apps that have no supportedArchitectures specified', async () => {
// Arrange
setConfig('architecture', AppSupportedArchitecturesEnum.ARM);
const app3 = await createApp({});
// @ts-ignore
fs.__createMockFiles(Object.assign(app3.MockFiles));
// Act
const { apps } = await AppsService.listApps();
// Assert
expect(apps).toBeDefined();
expect(apps.length).toBe(1);
});
});
describe('Start all apps', () => {

View file

@ -26,6 +26,10 @@ export const checkAppRequirements = async (appName: string) => {
}
}
if (configFile?.supported_architectures && !configFile.supported_architectures.includes(getConfig().architecture)) {
throw new Error(`App ${appName} is not supported on this architecture`);
}
return valid;
};

View file

@ -9,6 +9,18 @@ import { getConfig } from '../../core/config/TipiConfig';
import { eventDispatcher, EventTypes } from '../../core/config/EventDispatcher';
const sortApps = (a: AppInfo, b: AppInfo) => a.name.localeCompare(b.name);
const filterApp = (app: AppInfo): boolean => {
if (!app.supported_architectures) {
return true;
}
const arch = getConfig().architecture;
return app.supported_architectures.includes(arch);
};
const filterApps = (apps: AppInfo[]): AppInfo[] => {
return apps.sort(sortApps).filter(filterApp);
};
/**
* Start all apps which had the status RUNNING in the database
@ -159,7 +171,7 @@ const listApps = async (): Promise<ListAppsResonse> => {
app.description = readFile(`/runtipi/repos/${getConfig().appsRepoId}/apps/${app.id}/metadata/description.md`);
});
return { apps: apps.sort(sortApps), total: apps.length };
return { apps: filterApps(apps), total: apps.length };
};
/**

View file

@ -41,6 +41,12 @@ export enum AppStatusEnum {
UPDATING = 'updating',
}
export enum AppSupportedArchitecturesEnum {
ARM = 'arm',
ARM64 = 'arm64',
AMD64 = 'amd64',
}
registerEnumType(AppCategoriesEnum, {
name: 'AppCategoriesEnum',
});
@ -49,6 +55,10 @@ registerEnumType(FieldTypes, {
name: 'FieldTypesEnum',
});
registerEnumType(AppSupportedArchitecturesEnum, {
name: 'AppSupportedArchitecturesEnum',
});
@ObjectType()
class FormField {
@Field(() => FieldTypes)
@ -128,6 +138,9 @@ class AppInfo {
@Field(() => Boolean, { nullable: true })
exposable?: boolean;
@Field(() => [AppSupportedArchitecturesEnum], { nullable: true })
supported_architectures?: AppSupportedArchitecturesEnum[];
}
@ObjectType()

View file

@ -27,12 +27,16 @@ let corsOptions = {
return callback(null, true);
}
// disallow requests with no origin
if (!origin) return callback(new Error('Not allowed by CORS'), false);
if (!origin) {
logger.error('No origin');
return callback(new Error('Not allowed by CORS'), false);
}
if (getConfig().clientUrls.includes(origin)) {
return callback(null, true);
}
logger.error(`Origin ${origin} not allowed by CORS`);
const message = "The CORS policy for this origin doesn't allow access from the particular origin.";
return callback(new Error(message), false);
},
@ -103,6 +107,7 @@ const main = async () => {
// Start apps
appsService.startAllApps();
logger.info(`Server running on port ${port} 🚀 Production => ${__prod__}`);
logger.info(`Config: ${JSON.stringify(getConfig(), null, 2)}`);
});
} catch (error) {
logger.error(error);

137
pnpm-lock.yaml generated
View file

@ -49,7 +49,7 @@ importers:
graphql: ^15.8.0
graphql-tag: ^2.12.6
jest: ^28.1.0
next: 12.1.6
next: 12.3.1
postcss: ^8.4.12
react: 18.1.0
react-dom: 18.1.0
@ -78,7 +78,7 @@ importers:
framer-motion: 6.3.3_ef5jwxihqo6n7gxfmzogljlgcm
graphql: 15.8.0
graphql-tag: 2.12.6_graphql@15.8.0
next: 12.1.6_talmm3uuvp6ssixt2qevhfgvue
next: 12.3.1_talmm3uuvp6ssixt2qevhfgvue
react: 18.1.0
react-dom: 18.1.0_react@18.1.0
react-final-form: 6.5.9_bnxchjdfy45cdln7bu7hnhf37u
@ -109,7 +109,7 @@ importers:
autoprefixer: 10.4.7_postcss@8.4.13
eslint: 8.12.0
eslint-config-airbnb-typescript: 17.0.0_r46exuh3jlhq2wmrnqx2ufqspa
eslint-config-next: 12.1.4_e6a2zi6fqdwfehht5cxvkmo3zu
eslint-config-next: 12.1.4_c2ous3fcmy6f3xlzfnkf2jzbvm
eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy
jest: 28.1.0_@types+node@17.0.31
postcss: 8.4.13
@ -3169,8 +3169,8 @@ packages:
graphql: 15.8.0
dev: true
/@next/env/12.1.6:
resolution: {integrity: sha512-Te/OBDXFSodPU6jlXYPAXpmZr/AkG6DCATAxttQxqOWaq6eDFX25Db3dK0120GZrSZmv4QCe9KsZmJKDbWs4OA==}
/@next/env/12.3.1:
resolution: {integrity: sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==}
dev: false
/@next/eslint-plugin-next/12.1.4:
@ -3179,8 +3179,8 @@ packages:
glob: 7.1.7
dev: true
/@next/swc-android-arm-eabi/12.1.6:
resolution: {integrity: sha512-BxBr3QAAAXWgk/K7EedvzxJr2dE014mghBSA9iOEAv0bMgF+MRq4PoASjuHi15M2zfowpcRG8XQhMFtxftCleQ==}
/@next/swc-android-arm-eabi/12.3.1:
resolution: {integrity: sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==}
engines: {node: '>= 10'}
cpu: [arm]
os: [android]
@ -3188,8 +3188,8 @@ packages:
dev: false
optional: true
/@next/swc-android-arm64/12.1.6:
resolution: {integrity: sha512-EboEk3ROYY7U6WA2RrMt/cXXMokUTXXfnxe2+CU+DOahvbrO8QSWhlBl9I9ZbFzJx28AGB9Yo3oQHCvph/4Lew==}
/@next/swc-android-arm64/12.3.1:
resolution: {integrity: sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
@ -3197,8 +3197,8 @@ packages:
dev: false
optional: true
/@next/swc-darwin-arm64/12.1.6:
resolution: {integrity: sha512-P0EXU12BMSdNj1F7vdkP/VrYDuCNwBExtRPDYawgSUakzi6qP0iKJpya2BuLvNzXx+XPU49GFuDC5X+SvY0mOw==}
/@next/swc-darwin-arm64/12.3.1:
resolution: {integrity: sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
@ -3206,8 +3206,8 @@ packages:
dev: false
optional: true
/@next/swc-darwin-x64/12.1.6:
resolution: {integrity: sha512-9FptMnbgHJK3dRDzfTpexs9S2hGpzOQxSQbe8omz6Pcl7rnEp9x4uSEKY51ho85JCjL4d0tDLBcXEJZKKLzxNg==}
/@next/swc-darwin-x64/12.3.1:
resolution: {integrity: sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
@ -3215,8 +3215,17 @@ packages:
dev: false
optional: true
/@next/swc-linux-arm-gnueabihf/12.1.6:
resolution: {integrity: sha512-PvfEa1RR55dsik/IDkCKSFkk6ODNGJqPY3ysVUZqmnWMDSuqFtf7BPWHFa/53znpvVB5XaJ5Z1/6aR5CTIqxPw==}
/@next/swc-freebsd-x64/12.3.1:
resolution: {integrity: sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: false
optional: true
/@next/swc-linux-arm-gnueabihf/12.3.1:
resolution: {integrity: sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
@ -3224,8 +3233,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-arm64-gnu/12.1.6:
resolution: {integrity: sha512-53QOvX1jBbC2ctnmWHyRhMajGq7QZfl974WYlwclXarVV418X7ed7o/EzGY+YVAEKzIVaAB9JFFWGXn8WWo0gQ==}
/@next/swc-linux-arm64-gnu/12.3.1:
resolution: {integrity: sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@ -3233,8 +3242,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-arm64-musl/12.1.6:
resolution: {integrity: sha512-CMWAkYqfGdQCS+uuMA1A2UhOfcUYeoqnTW7msLr2RyYAys15pD960hlDfq7QAi8BCAKk0sQ2rjsl0iqMyziohQ==}
/@next/swc-linux-arm64-musl/12.3.1:
resolution: {integrity: sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@ -3242,8 +3251,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-x64-gnu/12.1.6:
resolution: {integrity: sha512-AC7jE4Fxpn0s3ujngClIDTiEM/CQiB2N2vkcyWWn6734AmGT03Duq6RYtPMymFobDdAtZGFZd5nR95WjPzbZAQ==}
/@next/swc-linux-x64-gnu/12.3.1:
resolution: {integrity: sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@ -3251,8 +3260,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-x64-musl/12.1.6:
resolution: {integrity: sha512-c9Vjmi0EVk0Kou2qbrynskVarnFwfYIi+wKufR9Ad7/IKKuP6aEhOdZiIIdKsYWRtK2IWRF3h3YmdnEa2WLUag==}
/@next/swc-linux-x64-musl/12.3.1:
resolution: {integrity: sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@ -3260,8 +3269,8 @@ packages:
dev: false
optional: true
/@next/swc-win32-arm64-msvc/12.1.6:
resolution: {integrity: sha512-3UTOL/5XZSKFelM7qN0it35o3Cegm6LsyuERR3/OoqEExyj3aCk7F025b54/707HTMAnjlvQK3DzLhPu/xxO4g==}
/@next/swc-win32-arm64-msvc/12.3.1:
resolution: {integrity: sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
@ -3269,8 +3278,8 @@ packages:
dev: false
optional: true
/@next/swc-win32-ia32-msvc/12.1.6:
resolution: {integrity: sha512-8ZWoj6nCq6fI1yCzKq6oK0jE6Mxlz4MrEsRyu0TwDztWQWe7rh4XXGLAa2YVPatYcHhMcUL+fQQbqd1MsgaSDA==}
/@next/swc-win32-ia32-msvc/12.3.1:
resolution: {integrity: sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
@ -3278,8 +3287,8 @@ packages:
dev: false
optional: true
/@next/swc-win32-x64-msvc/12.1.6:
resolution: {integrity: sha512-4ZEwiRuZEicXhXqmhw3+de8Z4EpOLQj/gp+D9fFWo6ii6W1kBkNNvvEx4A90ugppu+74pT1lIJnOuz3A9oQeJA==}
/@next/swc-win32-x64-msvc/12.3.1:
resolution: {integrity: sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@ -3562,6 +3571,12 @@ packages:
'@swc/core-win32-x64-msvc': 1.2.210
dev: true
/@swc/helpers/0.4.11:
resolution: {integrity: sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==}
dependencies:
tslib: 2.4.0
dev: false
/@szmarczak/http-timer/1.1.2:
resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==}
engines: {node: '>=6'}
@ -5047,6 +5062,11 @@ packages:
/caniuse-lite/1.0.30001338:
resolution: {integrity: sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ==}
dev: true
/caniuse-lite/1.0.30001419:
resolution: {integrity: sha512-aFO1r+g6R7TW+PNQxKzjITwLOyDhVRLjW0LcwS/HCZGUUKTGNp9+IwLC4xyDSZBygVL/mxaFR3HIV6wEKQuSzw==}
dev: false
/capital-case/1.0.4:
resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==}
@ -6119,7 +6139,7 @@ packages:
eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy
dev: true
/eslint-config-next/12.1.4_e6a2zi6fqdwfehht5cxvkmo3zu:
/eslint-config-next/12.1.4_c2ous3fcmy6f3xlzfnkf2jzbvm:
resolution: {integrity: sha512-Uj0jrVjoQbg9qerxRjSHoOOv3PEzoZxpb8G9LYct25fsflP8xIiUq0l4WEu2KSB5owuLv5hie7wSMqPEsHj+bQ==}
peerDependencies:
eslint: ^7.23.0 || ^8.0.0
@ -6139,7 +6159,7 @@ packages:
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
next: 12.3.1_talmm3uuvp6ssixt2qevhfgvue
typescript: 4.6.4
transitivePeerDependencies:
- eslint-import-resolver-webpack
@ -9686,8 +9706,8 @@ packages:
engines: {node: '>= 0.6'}
dev: false
/next/12.1.6_talmm3uuvp6ssixt2qevhfgvue:
resolution: {integrity: sha512-cebwKxL3/DhNKfg9tPZDQmbRKjueqykHHbgaoG4VBRH3AHQJ2HO0dbKFiS1hPhe1/qgc2d/hFeadsbPicmLD+A==}
/next/12.3.1_talmm3uuvp6ssixt2qevhfgvue:
resolution: {integrity: sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==}
engines: {node: '>=12.22.0'}
hasBin: true
peerDependencies:
@ -9704,25 +9724,28 @@ packages:
sass:
optional: true
dependencies:
'@next/env': 12.1.6
caniuse-lite: 1.0.30001338
postcss: 8.4.5
'@next/env': 12.3.1
'@swc/helpers': 0.4.11
caniuse-lite: 1.0.30001419
postcss: 8.4.14
react: 18.1.0
react-dom: 18.1.0_react@18.1.0
styled-jsx: 5.0.2_vm2wkhzl5f5eyl7hfuywll6uzq
styled-jsx: 5.0.7_vm2wkhzl5f5eyl7hfuywll6uzq
use-sync-external-store: 1.2.0_react@18.1.0
optionalDependencies:
'@next/swc-android-arm-eabi': 12.1.6
'@next/swc-android-arm64': 12.1.6
'@next/swc-darwin-arm64': 12.1.6
'@next/swc-darwin-x64': 12.1.6
'@next/swc-linux-arm-gnueabihf': 12.1.6
'@next/swc-linux-arm64-gnu': 12.1.6
'@next/swc-linux-arm64-musl': 12.1.6
'@next/swc-linux-x64-gnu': 12.1.6
'@next/swc-linux-x64-musl': 12.1.6
'@next/swc-win32-arm64-msvc': 12.1.6
'@next/swc-win32-ia32-msvc': 12.1.6
'@next/swc-win32-x64-msvc': 12.1.6
'@next/swc-android-arm-eabi': 12.3.1
'@next/swc-android-arm64': 12.3.1
'@next/swc-darwin-arm64': 12.3.1
'@next/swc-darwin-x64': 12.3.1
'@next/swc-freebsd-x64': 12.3.1
'@next/swc-linux-arm-gnueabihf': 12.3.1
'@next/swc-linux-arm64-gnu': 12.3.1
'@next/swc-linux-arm64-musl': 12.3.1
'@next/swc-linux-x64-gnu': 12.3.1
'@next/swc-linux-x64-musl': 12.3.1
'@next/swc-win32-arm64-msvc': 12.3.1
'@next/swc-win32-ia32-msvc': 12.3.1
'@next/swc-win32-x64-msvc': 12.3.1
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
@ -10371,8 +10394,8 @@ packages:
source-map-js: 1.0.2
dev: true
/postcss/8.4.5:
resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==}
/postcss/8.4.14:
resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.4
@ -11453,8 +11476,8 @@ packages:
tslib: 2.4.0
dev: false
/styled-jsx/5.0.2_vm2wkhzl5f5eyl7hfuywll6uzq:
resolution: {integrity: sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==}
/styled-jsx/5.0.7_vm2wkhzl5f5eyl7hfuywll6uzq:
resolution: {integrity: sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==}
engines: {node: '>= 12.0.0'}
peerDependencies:
'@babel/core': '*'
@ -12289,6 +12312,14 @@ packages:
tslib: 2.4.0
dev: false
/use-sync-external-store/1.2.0_react@18.1.0:
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
react: 18.1.0
dev: false
/util-deprecate/1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}

View file

@ -141,9 +141,13 @@ if [[ "$command" = "uninstall" ]]; then
write_log "Failed to uninstall app ${app}"
exit 1
fi
if ! compose "${app}" down --rmi all --remove-orphans; then
write_log "Failed to uninstall app ${app}"
exit 1
# just stop it if we can't remove the images
if ! compose "${app}" rm --force --stop; then
write_log "Failed to uninstall app ${app}"
exit 1
fi
fi
write_log "Deleting app data for app ${app}..."
@ -167,8 +171,11 @@ if [[ "$command" = "update" ]]; then
fi
if ! compose "${app}" down --rmi all --remove-orphans; then
write_log "Failed to update app ${app}"
exit 1
# just stop it if we can't remove the images
if ! compose "${app}" rm --force --stop; then
write_log "Failed to uninstall app ${app}"
exit 1
fi
fi
# Remove app
@ -214,4 +221,12 @@ if [[ "$command" = "compose" ]]; then
exit 0
fi
if [[ "$command" = "clean" ]]; then
# Remove all stopped containers and unused images
write_log "Cleaning up..."
docker system prune --all --force
exit 0
fi
exit 1

View file

@ -55,7 +55,7 @@ if [[ "$command" = "update" ]]; then
write_log "Updating ${repo} in ${repo_hash}"
cd "${repo_dir}" || exit
if ! git pull origin master; then
if ! git pull origin "$(git rev-parse --abbrev-ref HEAD)"; then
cd "${ROOT_FOLDER}" || exit
write_log "Failed to update repo"
exit 1

View file

@ -12,7 +12,7 @@ SED_ROOT_FOLDER="$(echo "$ROOT_FOLDER" | sed 's/\//\\\//g')"
NGINX_PORT=80
NGINX_PORT_SSL=443
DOMAIN=tipi.localhost
DNS_IP=9.9.9.9 # Default to Quad9 DNS
DNS_IP="9.9.9.9" # Default to Quad9 DNS
ARCHITECTURE="$(uname -m)"
TZ="UTC"
JWT_SECRET=secret
@ -21,6 +21,18 @@ TIPI_VERSION=$(get_json_field "${ROOT_FOLDER}/package.json" version)
INTERNAL_IP=localhost
storage_path="${ROOT_FOLDER}"
STORAGE_PATH_ESCAPED="$(echo "${storage_path}" | sed 's/\//\\\//g')"
if [[ "$ARCHITECTURE" == "aarch64" ]]; then
ARCHITECTURE="arm64"
elif [[ "$ARCHITECTURE" == "armv7l" ]]; then
ARCHITECTURE="arm"
elif [[ "$ARCHITECTURE" == "x86_64" ]]; then
ARCHITECTURE="amd64"
fi
# If none of the above conditions are met, the architecture is not supported
if [[ "$ARCHITECTURE" != "arm64" ]] && [[ "$ARCHITECTURE" != "arm" ]] && [[ "$ARCHITECTURE" != "amd64" ]]; then
echo "Architecture not supported!"
exit 1
fi
### --------------------------------
### Apps repository configuration

View file

@ -12,7 +12,9 @@ ensure_pwd
ensure_root
clean_logs
# Configure Tipi
### --------------------------------
### Pre-configuration
### --------------------------------
"${ROOT_FOLDER}/scripts/configure.sh"
STATE_FOLDER="${ROOT_FOLDER}/state"
@ -22,12 +24,14 @@ if [[ ! -f "${STATE_FOLDER}/seed" ]]; then
tr </dev/urandom -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 >"${STATE_FOLDER}/seed"
fi
# Default variables
### --------------------------------
### General variables
### --------------------------------
NGINX_PORT=80
NGINX_PORT_SSL=443
DOMAIN=tipi.localhost
SED_ROOT_FOLDER="$(echo "$ROOT_FOLDER" | sed 's/\//\\\//g')"
DNS_IP=9.9.9.9 # Default to Quad9 DNS
DNS_IP="9.9.9.9" # Default to Quad9 DNS
ARCHITECTURE="$(uname -m)"
TZ="$(timedatectl | grep "Time zone" | awk '{print $3}' | sed 's/\//\\\//g' || Europe\/Berlin)"
apps_repository="https://github.com/meienberger/runtipi-appstore"
@ -61,6 +65,16 @@ INTERNAL_IP="$(ip addr show "${NETWORK_INTERFACE}" | grep "inet " | awk '{print
if [[ "$ARCHITECTURE" == "aarch64" ]]; then
ARCHITECTURE="arm64"
elif [[ "$ARCHITECTURE" == "armv7"* || "$ARCHITECTURE" == "armv8"* ]]; then
ARCHITECTURE="arm"
elif [[ "$ARCHITECTURE" == "x86_64" ]]; then
ARCHITECTURE="amd64"
fi
# If none of the above conditions are met, the architecture is not supported
if [[ "$ARCHITECTURE" != "arm64" ]] && [[ "$ARCHITECTURE" != "arm" ]] && [[ "$ARCHITECTURE" != "amd64" ]]; then
echo "Architecture ${ARCHITECTURE} not supported!"
exit 1
fi
### --------------------------------
@ -129,21 +143,18 @@ if [[ "${NGINX_PORT}" != "80" ]] && [[ "${DOMAIN}" != "tipi.localhost" ]]; then
exit 1
fi
# Run system-info.sh
### --------------------------------
### Watcher and system-info
### --------------------------------
echo "Running system-info.sh..."
"${ROOT_FOLDER}/scripts/system-info.sh"
kill_watcher
"${ROOT_FOLDER}/scripts/watcher.sh" &
# Copy the config sample if it isn't here
if [[ ! -f "${STATE_FOLDER}/apps.json" ]]; then
cp "${ROOT_FOLDER}/templates/config-sample.json" "${STATE_FOLDER}/config.json"
fi
export DOCKER_CLIENT_TIMEOUT=240
export COMPOSE_HTTP_TIMEOUT=240
### --------------------------------
### settings.json overrides
### --------------------------------
echo "Generating config files..."
# Override vars with values from settings.json
if [[ -f "${STATE_FOLDER}/settings.json" ]]; then
@ -216,7 +227,9 @@ done
mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
## Don't run if config-only
### --------------------------------
### Start the project
### --------------------------------
if [[ ! $ci == "true" ]]; then
if [[ $rc == "true" ]]; then

View file

@ -27,7 +27,7 @@ if [[ "$command" = "update" ]]; then
scripts/stop.sh
git config --global --add safe.directory "${ROOT_FOLDER}"
git pull origin master
git pull origin "$(git rev-parse --abbrev-ref HEAD)"
scripts/start.sh
exit
fi