ci: automerge minor and patch app upgrades (#720)
* fix: app version mismatchs between config and docker-compose * ci: create automerge workflow wip
This commit is contained in:
parent
c354f1f094
commit
e495cc1293
28
.github/workflows/auto-merge.yml
vendored
Normal file
28
.github/workflows/auto-merge.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
name: automerge
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- labeled
|
||||||
|
- unlabeled
|
||||||
|
- synchronize
|
||||||
|
- opened
|
||||||
|
- edited
|
||||||
|
- ready_for_review
|
||||||
|
- reopened
|
||||||
|
- unlocked
|
||||||
|
pull_request_review:
|
||||||
|
types:
|
||||||
|
- submitted
|
||||||
|
check_suite:
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
status: {}
|
||||||
|
jobs:
|
||||||
|
automerge:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- id: automerge
|
||||||
|
name: automerge
|
||||||
|
uses: "pascalgn/automerge-action@v0.15.6"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
72
.github/workflows/ci.yml
vendored
72
.github/workflows/ci.yml
vendored
|
@ -1,9 +1,8 @@
|
||||||
name: Tipi CI
|
name: Tipi CI
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened, ready_for_review]
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -26,7 +25,7 @@ jobs:
|
||||||
- name: Get pnpm store directory
|
- name: Get pnpm store directory
|
||||||
id: pnpm-cache
|
id: pnpm-cache
|
||||||
run: |
|
run: |
|
||||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
name: Setup pnpm cache
|
name: Setup pnpm cache
|
||||||
|
@ -44,3 +43,70 @@ jobs:
|
||||||
|
|
||||||
- name: Run linter
|
- name: Run linter
|
||||||
run: pnpm run lint
|
run: pnpm run lint
|
||||||
|
|
||||||
|
- name: Check bumped version
|
||||||
|
id: check-bumped-version
|
||||||
|
uses: actions/github-script@v4
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const semver = require('semver')
|
||||||
|
const { data } = await github.pulls.listFiles({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
pull_number: context.issue.number
|
||||||
|
});
|
||||||
|
|
||||||
|
const modifiedFiles = data.map(file => file.filename);
|
||||||
|
const filesInAppsFolder = modifiedFiles.filter(file => file.includes('apps/'))
|
||||||
|
|
||||||
|
if (filesInAppsFolder.length < modifiedFiles.length) {
|
||||||
|
console.log('Not all files are in apps folder, skipping automerge')
|
||||||
|
core.setOutput('major_bump', 'true')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const configs = modifiedFiles.filter(file => file.includes('config.json'))
|
||||||
|
let majorBump = 'false'
|
||||||
|
|
||||||
|
for (const configFile of configs) {
|
||||||
|
const baseContent = await github.repos.getContent({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
path: configFile,
|
||||||
|
ref: context.payload.pull_request.base.ref
|
||||||
|
});
|
||||||
|
const baseConfig = JSON.parse(Buffer.from(baseContent.data.content, 'base64').toString('utf-8'))
|
||||||
|
|
||||||
|
const currentContent = await github.repos.getContent({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
path: configFile,
|
||||||
|
ref: context.payload.pull_request.head.ref
|
||||||
|
});
|
||||||
|
const currentConfig = JSON.parse(Buffer.from(currentContent.data.content, 'base64').toString('utf-8'))
|
||||||
|
|
||||||
|
const baseVersion = semver.coerce(baseConfig.version)
|
||||||
|
const currentVersion = semver.coerce(currentConfig.version)
|
||||||
|
|
||||||
|
if (currentVersion?.major > baseVersion?.major) {
|
||||||
|
console.log('Major bump detected, skipping automerge')
|
||||||
|
majorBump = 'true'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.setOutput('major_bump', majorBump)
|
||||||
|
|
||||||
|
- name: Label this PR as "automerge" if major_bump is false
|
||||||
|
if: steps.check-bumped-version.outputs.major_bump == 'false'
|
||||||
|
uses: actions/github-script@v4
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
github.issues.addLabels({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
labels: ["automerge"]
|
||||||
|
})
|
||||||
|
|
2
.github/workflows/renovate-app-version.yml
vendored
2
.github/workflows/renovate-app-version.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
- name: Get list of updated files by the last commit in this branch separated by space
|
- name: Get list of updated files by the last commit in this branch separated by space
|
||||||
id: updated-files
|
id: updated-files
|
||||||
run: |
|
run: |
|
||||||
echo "::set-output name=files::$(git diff-tree --no-commit-id --name-only -r ${{ github.sha }} | tr '\n' ' ')"
|
echo "files=$(git diff-tree --no-commit-id --name-only -r ${{ github.sha }} | tr '\n' ' ')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Run renovate-app-version.sh on updated files
|
- name: Run renovate-app-version.sh on updated files
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import fs from 'fs';
|
import fs from "fs";
|
||||||
import jsyaml from 'js-yaml';
|
import semver from "semver";
|
||||||
|
import jsyaml from "js-yaml";
|
||||||
|
|
||||||
interface AppConfig {
|
interface AppConfig {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -18,11 +19,18 @@ interface AppConfig {
|
||||||
available: boolean;
|
available: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const networkExceptions = ['pihole', 'tailscale', 'homeassistant', 'plex', 'zerotier', 'gladys'];
|
const networkExceptions = [
|
||||||
|
"pihole",
|
||||||
|
"tailscale",
|
||||||
|
"homeassistant",
|
||||||
|
"plex",
|
||||||
|
"zerotier",
|
||||||
|
"gladys",
|
||||||
|
];
|
||||||
const getAppConfigs = (): AppConfig[] => {
|
const getAppConfigs = (): AppConfig[] => {
|
||||||
const apps: AppConfig[] = [];
|
const apps: AppConfig[] = [];
|
||||||
|
|
||||||
const appsDir = fs.readdirSync('./apps');
|
const appsDir = fs.readdirSync("./apps");
|
||||||
|
|
||||||
appsDir.forEach((app: string) => {
|
appsDir.forEach((app: string) => {
|
||||||
const path = `./apps/${app}/config.json`;
|
const path = `./apps/${app}/config.json`;
|
||||||
|
@ -36,7 +44,7 @@ const getAppConfigs = (): AppConfig[] => {
|
||||||
apps.push(config);
|
apps.push(config);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error parsing config file', app);
|
console.error("Error parsing config file", app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -44,152 +52,198 @@ const getAppConfigs = (): AppConfig[] => {
|
||||||
return apps;
|
return apps;
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('App configs', () => {
|
describe("App configs", () => {
|
||||||
it('Get app config should return at least one app', () => {
|
it("Get app config should return at least one app", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
expect(apps.length).toBeGreaterThan(0);
|
expect(apps.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have an id', () => {
|
describe("Each app should have an id", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(app.id).toBeDefined();
|
test(app.id, () => {
|
||||||
|
expect(app.id).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a md description', () => {
|
describe("Each app should have a md description", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
const path = `./apps/${app.id}/metadata/description.md`;
|
test(app.id, () => {
|
||||||
|
const path = `./apps/${app.id}/metadata/description.md`;
|
||||||
|
|
||||||
if (fs.existsSync(path)) {
|
if (fs.existsSync(path)) {
|
||||||
const description = fs.readFileSync(path).toString();
|
const description = fs.readFileSync(path).toString();
|
||||||
expect(description).toBeDefined();
|
expect(description).toBeDefined();
|
||||||
} else {
|
} else {
|
||||||
console.error(`Missing description for app ${app.id}`);
|
expect(true).toBe(false);
|
||||||
expect(true).toBe(false);
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have categories defined as an array', () => {
|
describe("Each app should have categories defined as an array", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(app.categories).toBeDefined();
|
test(app.id, () => {
|
||||||
expect(app.categories).toBeInstanceOf(Array);
|
expect(app.categories).toBeDefined();
|
||||||
|
expect(app.categories).toBeInstanceOf(Array);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a name', () => {
|
describe("Each app should have a name", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(app.name).toBeDefined();
|
test(app.id, () => {
|
||||||
|
expect(app.name).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a description', () => {
|
describe("Each app should have a description", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(app.description).toBeDefined();
|
test(app.id, () => {
|
||||||
|
expect(app.description).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a port', () => {
|
describe("Each app should have a port", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(app.port).toBeDefined();
|
test(app.id, () => {
|
||||||
expect(app.port).toBeGreaterThan(999);
|
expect(app.port).toBeDefined();
|
||||||
expect(app.port).toBeLessThan(65535);
|
expect(app.port).toBeGreaterThan(999);
|
||||||
|
expect(app.port).toBeLessThan(65535);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a different port', () => {
|
test("Each app should have a different port", () => {
|
||||||
const appConfigs = getAppConfigs();
|
const appConfigs = getAppConfigs();
|
||||||
const ports = appConfigs.map((app) => app.port);
|
const ports = appConfigs.map((app) => app.port);
|
||||||
expect(new Set(ports).size).toBe(appConfigs.length);
|
expect(new Set(ports).size).toBe(appConfigs.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a unique id', () => {
|
test("Each app should have a unique id", () => {
|
||||||
const appConfigs = getAppConfigs();
|
const appConfigs = getAppConfigs();
|
||||||
const ids = appConfigs.map((app) => app.id);
|
const ids = appConfigs.map((app) => app.id);
|
||||||
expect(new Set(ids).size).toBe(appConfigs.length);
|
expect(new Set(ids).size).toBe(appConfigs.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a version', () => {
|
describe("Each app should have a version", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(app.tipi_version).toBeDefined();
|
test(app.id, () => {
|
||||||
expect(app.tipi_version).toBeGreaterThan(0);
|
expect(app.version).toBeDefined();
|
||||||
|
expect(app.tipi_version).toBeDefined();
|
||||||
|
expect(app.tipi_version).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a docker-compose file beside it', () => {
|
describe("Each app should have a docker-compose file beside it", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(fs.existsSync(`./apps/${app.id}/docker-compose.yml`)).toBe(true);
|
test(app.id, () => {
|
||||||
|
expect(fs.existsSync(`./apps/${app.id}/docker-compose.yml`)).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a metadata folder beside it', () => {
|
describe("Each app should have a metadata folder beside it", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(fs.existsSync(`./apps/${app.id}/metadata`)).toBe(true);
|
test(app.id, () => {
|
||||||
|
expect(fs.existsSync(`./apps/${app.id}/metadata`)).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a file named logo.jpg in the metadata folder', () => {
|
describe("Each app should have a file named logo.jpg in the metadata folder", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
expect(fs.existsSync(`./apps/${app.id}/metadata/logo.jpg`)).toBe(true);
|
test(app.id, () => {
|
||||||
|
expect(fs.existsSync(`./apps/${app.id}/metadata/logo.jpg`)).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Each app should have a container name equals to its id', () => {
|
describe("Each app should have a container name equals to its id", () => {
|
||||||
const apps = getAppConfigs();
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
apps.forEach((app) => {
|
apps.forEach((app) => {
|
||||||
const dockerComposeFile = fs.readFileSync(`./apps/${app.id}/docker-compose.yml`).toString();
|
test(app.id, () => {
|
||||||
|
const dockerComposeFile = fs
|
||||||
const dockerCompose: any = jsyaml.load(dockerComposeFile);
|
.readFileSync(`./apps/${app.id}/docker-compose.yml`)
|
||||||
|
.toString();
|
||||||
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);
|
const dockerCompose: any = jsyaml.load(dockerComposeFile);
|
||||||
|
|
||||||
expect(dockerCompose.services[app.id]).toBeDefined();
|
expect(dockerCompose.services[app.id]).toBeDefined();
|
||||||
|
expect(dockerCompose.services[app.id].container_name).toBe(app.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (!dockerCompose.services[app.id].networks) {
|
describe("Each app should have the same version in config.json and docker-compose.yml", () => {
|
||||||
console.error(app.id);
|
const exceptions = ["revolt"];
|
||||||
|
const apps = getAppConfigs().filter((app) => !exceptions.includes(app.id));
|
||||||
|
|
||||||
|
apps.forEach((app) => {
|
||||||
|
test(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();
|
||||||
|
expect(dockerCompose.services[app.id].image).toBeDefined();
|
||||||
|
|
||||||
|
const dockerImage = dockerCompose.services[app.id].image;
|
||||||
|
|
||||||
|
const version = dockerImage.split(":")[1];
|
||||||
|
|
||||||
|
expect(version).toContain(app.version);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Each app should have network tipi_main_network", () => {
|
||||||
|
const apps = getAppConfigs();
|
||||||
|
|
||||||
|
apps.forEach((app) => {
|
||||||
|
test(app.id, () => {
|
||||||
|
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();
|
||||||
|
|
||||||
|
expect(dockerCompose.services[app.id].networks).toBeDefined();
|
||||||
|
expect(dockerCompose.services[app.id].networks).toStrictEqual([
|
||||||
|
"tipi_main_network",
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
expect(dockerCompose.services[app.id].networks).toBeDefined();
|
|
||||||
expect(dockerCompose.services[app.id].networks).toStrictEqual(['tipi_main_network']);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"available": true,
|
"available": true,
|
||||||
"exposable": true,
|
"exposable": true,
|
||||||
"tipi_version": 11,
|
"tipi_version": 11,
|
||||||
"version": "0.107.32",
|
"version": "v0.107.32",
|
||||||
"port": 8104,
|
"port": 8104,
|
||||||
"id": "adguard",
|
"id": "adguard",
|
||||||
"categories": [
|
"categories": [
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
"exposable": true,
|
"exposable": true,
|
||||||
"id": "autobrr",
|
"id": "autobrr",
|
||||||
"tipi_version": 6,
|
"tipi_version": 6,
|
||||||
"version": "1.26.1",
|
"version": "v1.26.2",
|
||||||
"categories": ["media"],
|
"categories": [
|
||||||
|
"media"
|
||||||
|
],
|
||||||
"description": "autobrr is the modern download automation tool for torrents. With inspiration and ideas from tools like trackarr, autodl-irssi and flexget we built one tool that can do it all, and then some.",
|
"description": "autobrr is the modern download automation tool for torrents. With inspiration and ideas from tools like trackarr, autodl-irssi and flexget we built one tool that can do it all, and then some.",
|
||||||
"short_desc": "Automation for downloads.",
|
"short_desc": "Automation for downloads.",
|
||||||
"author": "autobrr",
|
"author": "autobrr",
|
||||||
|
|
|
@ -6,13 +6,17 @@
|
||||||
"exposable": true,
|
"exposable": true,
|
||||||
"id": "chatgpt-ui",
|
"id": "chatgpt-ui",
|
||||||
"tipi_version": 9,
|
"tipi_version": 9,
|
||||||
"version": "2.5.5",
|
"version": "v2.5.5",
|
||||||
"categories": ["ai"],
|
"categories": [
|
||||||
|
"ai"
|
||||||
|
],
|
||||||
"description": "A ChatGPT web client that supports multiple users, multiple languages, and multiple database connections for persistent data storage",
|
"description": "A ChatGPT web client that supports multiple users, multiple languages, and multiple database connections for persistent data storage",
|
||||||
"short_desc": "A ChatGPT web client that supports multiple users, multiple languages, and multiple database connections for persistent data storage",
|
"short_desc": "A ChatGPT web client that supports multiple users, multiple languages, and multiple database connections for persistent data storage",
|
||||||
"author": "https://github.com/WongSaang",
|
"author": "https://github.com/WongSaang",
|
||||||
"source": "https://github.com/WongSaang/chatgpt-ui",
|
"source": "https://github.com/WongSaang/chatgpt-ui",
|
||||||
"supported_architectures": ["amd64"],
|
"supported_architectures": [
|
||||||
|
"amd64"
|
||||||
|
],
|
||||||
"form_fields": [
|
"form_fields": [
|
||||||
{
|
{
|
||||||
"type": "random",
|
"type": "random",
|
||||||
|
|
|
@ -3,7 +3,7 @@ version: "3"
|
||||||
services:
|
services:
|
||||||
deemix:
|
deemix:
|
||||||
container_name: deemix
|
container_name: deemix
|
||||||
image: registry.gitlab.com/bockiii/deemix-docker
|
image: registry.gitlab.com/bockiii/deemix-docker:latest
|
||||||
ports:
|
ports:
|
||||||
- ${APP_PORT}:6595
|
- ${APP_PORT}:6595
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
"port": 8000,
|
"port": 8000,
|
||||||
"id": "hello-world",
|
"id": "hello-world",
|
||||||
"tipi_version": 2,
|
"tipi_version": 2,
|
||||||
"version": "1.0.0",
|
"version": "latest",
|
||||||
"categories": ["utilities"],
|
"categories": [
|
||||||
|
"utilities"
|
||||||
|
],
|
||||||
"description": "Hello World web server in under 2 MB",
|
"description": "Hello World web server in under 2 MB",
|
||||||
"short_desc": "Hello World web server in under 2 MB",
|
"short_desc": "Hello World web server in under 2 MB",
|
||||||
"author": "crccheck",
|
"author": "crccheck",
|
||||||
|
|
|
@ -2,7 +2,7 @@ version: "3.7"
|
||||||
services:
|
services:
|
||||||
hello-world:
|
hello-world:
|
||||||
container_name: hello-world
|
container_name: hello-world
|
||||||
image: crccheck/hello-world
|
image: crccheck/hello-world:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- ${APP_PORT}:8000
|
- ${APP_PORT}:8000
|
||||||
|
|
|
@ -3,7 +3,7 @@ version: "3.7"
|
||||||
services:
|
services:
|
||||||
minecraft-server:
|
minecraft-server:
|
||||||
container_name: minecraft-server
|
container_name: minecraft-server
|
||||||
image: itzg/minecraft-server
|
image: itzg/minecraft-server:latest
|
||||||
ports:
|
ports:
|
||||||
- ${APP_PORT}:25565
|
- ${APP_PORT}:25565
|
||||||
environment:
|
environment:
|
||||||
|
|
|
@ -6,13 +6,18 @@
|
||||||
"exposable": true,
|
"exposable": true,
|
||||||
"id": "mixpost-pro",
|
"id": "mixpost-pro",
|
||||||
"tipi_version": 6,
|
"tipi_version": 6,
|
||||||
"version": "0.7",
|
"version": "latest",
|
||||||
"categories": ["social", "utilities"],
|
"categories": [
|
||||||
|
"social",
|
||||||
|
"utilities"
|
||||||
|
],
|
||||||
"description": "Mixpost it's the coolest Self-hosted social media management software.",
|
"description": "Mixpost it's the coolest Self-hosted social media management software.",
|
||||||
"short_desc": "Self-hosted social media management. Schedule and organize your social content. ",
|
"short_desc": "Self-hosted social media management. Schedule and organize your social content. ",
|
||||||
"author": "Inovector",
|
"author": "Inovector",
|
||||||
"source": "https://github.com/inovector/mixpost",
|
"source": "https://github.com/inovector/mixpost",
|
||||||
"supported_architectures": ["amd64"],
|
"supported_architectures": [
|
||||||
|
"amd64"
|
||||||
|
],
|
||||||
"form_fields": [
|
"form_fields": [
|
||||||
{
|
{
|
||||||
"type": "random",
|
"type": "random",
|
||||||
|
|
|
@ -7,8 +7,11 @@
|
||||||
"id": "openbooks",
|
"id": "openbooks",
|
||||||
"tipi_version": 3,
|
"tipi_version": 3,
|
||||||
"url_suffix": "/openbooks/",
|
"url_suffix": "/openbooks/",
|
||||||
"version": "v4.5.0",
|
"version": "4.5.0",
|
||||||
"categories": ["media", "books"],
|
"categories": [
|
||||||
|
"media",
|
||||||
|
"books"
|
||||||
|
],
|
||||||
"description": "Openbooks allows you to download ebooks from irc.irchighway.net quickly and easily. ",
|
"description": "Openbooks allows you to download ebooks from irc.irchighway.net quickly and easily. ",
|
||||||
"short_desc": "Search and Download eBooks",
|
"short_desc": "Search and Download eBooks",
|
||||||
"author": "https://github.com/evan-buss",
|
"author": "https://github.com/evan-buss",
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
"social"
|
"social"
|
||||||
],
|
],
|
||||||
"description": "",
|
"description": "",
|
||||||
"tipi_version": 3,
|
"tipi_version": 4,
|
||||||
"version": "1.0.0",
|
"version": "2.4.9.2",
|
||||||
"short_desc": "Open source alternative frontend for TikTok made using PHP ",
|
"short_desc": "Open source alternative frontend for TikTok made using PHP ",
|
||||||
"author": "pablouser1",
|
"author": "pablouser1",
|
||||||
"source": "https://github.com/pablouser1/ProxiTok",
|
"source": "https://github.com/pablouser1/ProxiTok",
|
||||||
|
|
|
@ -3,7 +3,7 @@ services:
|
||||||
|
|
||||||
proxitok:
|
proxitok:
|
||||||
container_name: proxitok
|
container_name: proxitok
|
||||||
image: ghcr.io/pablouser1/proxitok:master
|
image: ghcr.io/pablouser1/proxitok:v2.4.9.2
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- ${APP_PORT}:80
|
- ${APP_PORT}:80
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
version: '3.7'
|
version: '3.7'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
vikunja-frontend:
|
vikunja:
|
||||||
depends_on:
|
depends_on:
|
||||||
- vikunja-api
|
- vikunja-api
|
||||||
container_name: vikunja-frontend
|
container_name: vikunja
|
||||||
image: vikunja/frontend:0.20.5
|
image: vikunja/frontend:0.20.5
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
|
@ -46,7 +46,7 @@ services:
|
||||||
networks:
|
networks:
|
||||||
- tipi_main_network
|
- tipi_main_network
|
||||||
|
|
||||||
vikunja:
|
vikunja-proxy:
|
||||||
container_name: vikunja
|
container_name: vikunja
|
||||||
image: nginx
|
image: nginx
|
||||||
ports:
|
ports:
|
||||||
|
|
|
@ -5,12 +5,9 @@
|
||||||
"exposable": true,
|
"exposable": true,
|
||||||
"port": 8103,
|
"port": 8103,
|
||||||
"id": "your-spotify",
|
"id": "your-spotify",
|
||||||
"tipi_version": 3,
|
"tipi_version": 4,
|
||||||
"version": "latest",
|
"version": "1.6.0",
|
||||||
"categories": [
|
"categories": ["music", "utilities"],
|
||||||
"music",
|
|
||||||
"utilities"
|
|
||||||
],
|
|
||||||
"description": "Self hosted Spotify tracking dashboard.",
|
"description": "Self hosted Spotify tracking dashboard.",
|
||||||
"short_desc": "Self hosted Spotify tracking dashboard.",
|
"short_desc": "Self hosted Spotify tracking dashboard.",
|
||||||
"author": "Yooooomi",
|
"author": "Yooooomi",
|
||||||
|
|
|
@ -3,7 +3,7 @@ version: "3"
|
||||||
services:
|
services:
|
||||||
your-spotify:
|
your-spotify:
|
||||||
container_name: your-spotify
|
container_name: your-spotify
|
||||||
image: yooooomi/your_spotify_client
|
image: yooooomi/your_spotify_client:1.6.0
|
||||||
depends_on:
|
depends_on:
|
||||||
- your-spotify-server
|
- your-spotify-server
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
"@types/jest": "^28.1.6",
|
"@types/jest": "^28.1.6",
|
||||||
"@types/js-yaml": "^4.0.5",
|
"@types/js-yaml": "^4.0.5",
|
||||||
"@types/node": "^18.6.2",
|
"@types/node": "^18.6.2",
|
||||||
|
"@types/semver": "^7.5.0",
|
||||||
"commitizen": "^4.2.5",
|
"commitizen": "^4.2.5",
|
||||||
"eslint": "^8.22.0",
|
"eslint": "^8.22.0",
|
||||||
"eslint-plugin-json-schema-validator": "^4.0.1",
|
"eslint-plugin-json-schema-validator": "^4.0.1",
|
||||||
|
@ -33,6 +34,8 @@
|
||||||
"husky": "^8.0.1",
|
"husky": "^8.0.1",
|
||||||
"jest": "^28.1.3",
|
"jest": "^28.1.3",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
"prettier": "^2.8.8",
|
||||||
|
"semver": "^7.5.2",
|
||||||
"ts-jest": "^28.0.7",
|
"ts-jest": "^28.0.7",
|
||||||
"typescript": "^4.7.4"
|
"typescript": "^4.7.4"
|
||||||
},
|
},
|
||||||
|
|
1237
pnpm-lock.yaml
1237
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user