mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-29 20:59:24 +00:00
Compare commits
87 Commits
v4.0.0-bet
...
v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b80a519b80 | ||
|
|
2fa7ffc931 | ||
|
|
4abec14a21 | ||
|
|
18d0623011 | ||
|
|
aa634c78d1 | ||
|
|
a2d4373104 | ||
|
|
702e16d643 | ||
|
|
3b25c8f96b | ||
|
|
1c8c567791 | ||
|
|
807a3c9d66 | ||
|
|
2abd7bd7bb | ||
|
|
343957ab8b | ||
|
|
49261308f7 | ||
|
|
d037409237 | ||
|
|
338cbf62a1 | ||
|
|
4c51bffc7b | ||
|
|
fd98ba8812 | ||
|
|
930251e9c8 | ||
|
|
7cd441266a | ||
|
|
990fb8ec15 | ||
|
|
3fe982b2f4 | ||
|
|
9dd874e959 | ||
|
|
b91368223b | ||
|
|
139670372b | ||
|
|
1c0769ad75 | ||
|
|
e6cbcf98cb | ||
|
|
64b0481055 | ||
|
|
ce15161926 | ||
|
|
4003d4d894 | ||
|
|
6e011025a7 | ||
|
|
6c0544adb2 | ||
|
|
8e4f7c9065 | ||
|
|
e71f890b54 | ||
|
|
4dc35dea97 | ||
|
|
b63dfb4bcd | ||
|
|
b2ffd9183b | ||
|
|
5cb0bcfd9b | ||
|
|
1fbcfcaf74 | ||
|
|
3ba44a1e23 | ||
|
|
de4efbb555 | ||
|
|
6f443680f3 | ||
|
|
23b22e5ca8 | ||
|
|
1bba747ce5 | ||
|
|
9ebfc6646e | ||
|
|
055ff6dbbd | ||
|
|
6430e7b288 | ||
|
|
87b0050161 | ||
|
|
369d8b408d | ||
|
|
505abc592c | ||
|
|
c9df812258 | ||
|
|
0bfcf6b66f | ||
|
|
67853acabd | ||
|
|
79c98657b1 | ||
|
|
d1be7e44af | ||
|
|
33b853b981 | ||
|
|
e6063fb93a | ||
|
|
f30f23af59 | ||
|
|
d4798a3b22 | ||
|
|
eefc2a3d0e | ||
|
|
d14ca724e9 | ||
|
|
7b05aaffc3 | ||
|
|
f3beb5d8db | ||
|
|
e86b916415 | ||
|
|
e14cc6f2f0 | ||
|
|
8c1eb94401 | ||
|
|
29fa421945 | ||
|
|
7cfe98d988 | ||
|
|
e2314c350b | ||
|
|
3713b33578 | ||
|
|
e007a773fd | ||
|
|
e2821118eb | ||
|
|
4c8e73ac86 | ||
|
|
cb980fb814 | ||
|
|
41c84e3642 | ||
|
|
2bad98424f | ||
|
|
bc6b1e2dea | ||
|
|
911c15d1be | ||
|
|
f79d570870 | ||
|
|
7fffa9fba5 | ||
|
|
cbd634fb99 | ||
|
|
7ae7436d4f | ||
|
|
641bada100 | ||
|
|
3416d8d88e | ||
|
|
0bb503368b | ||
|
|
ac3a77c3c7 | ||
|
|
79b4178d76 | ||
|
|
42a61296d7 |
@@ -1,8 +0,0 @@
|
|||||||
_____ _ _ __
|
|
||||||
/ ____| | (_)/ _|
|
|
||||||
| | ___ ___ | |_| |_ _ _
|
|
||||||
| | / _ \ / _ \| | | _| | | |
|
|
||||||
| |___| (_) | (_) | | | | | |_| |
|
|
||||||
\_____\___/ \___/|_|_|_| \__, |
|
|
||||||
__/ |
|
|
||||||
|___/
|
|
||||||
16
.devcontainer/Dockerfile
Normal file
16
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.233.0/containers/javascript-node/.devcontainer/base.Dockerfile
|
||||||
|
|
||||||
|
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
|
||||||
|
ARG VARIANT="16-bullseye"
|
||||||
|
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
|
||||||
|
|
||||||
|
# [Optional] Uncomment this section to install additional OS packages.
|
||||||
|
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||||
|
|
||||||
|
# [Optional] Uncomment if you want to install an additional version of node using nvm
|
||||||
|
# ARG EXTRA_NODE_VERSION=10
|
||||||
|
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
|
||||||
|
|
||||||
|
# [Optional] Uncomment if you want to install more global node modules
|
||||||
|
RUN su node -c "npm install -g pnpm"
|
||||||
36
.devcontainer/devcontainer.json
Normal file
36
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||||
|
// https://github.com/microsoft/vscode-dev-containers/tree/v0.233.0/containers/javascript-node
|
||||||
|
{
|
||||||
|
"name": "Node.js",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "Dockerfile",
|
||||||
|
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
|
||||||
|
// Append -bullseye or -buster to pin to an OS version.
|
||||||
|
// Use -bullseye variants on local arm64/Apple Silicon.
|
||||||
|
"args": {
|
||||||
|
"VARIANT": "18-bullseye"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Set *default* container specific settings.json values on container create.
|
||||||
|
"settings": {},
|
||||||
|
// Add the IDs of extensions you want installed when the container is created.
|
||||||
|
"extensions": [
|
||||||
|
"ms-azuretools.vscode-docker",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"svelte.svelte-vscode",
|
||||||
|
"ardenivanov.svelte-intellisense",
|
||||||
|
"Prisma.prisma",
|
||||||
|
"bradlc.vscode-tailwindcss",
|
||||||
|
"waderyan.gitblame"
|
||||||
|
],
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
"forwardPorts": [3000, 3001],
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
"postCreateCommand": "cp apps/api/.env.example apps/api/.env && pnpm install && pnpm db:push && pnpm db:seed",
|
||||||
|
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||||
|
"remoteUser": "node",
|
||||||
|
"features": {
|
||||||
|
"docker-in-docker": "20.10",
|
||||||
|
"github-cli": "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +1,16 @@
|
|||||||
/.phpunit.cache
|
.DS_Store
|
||||||
/node_modules
|
node_modules
|
||||||
/public/build
|
.pnpm-store
|
||||||
/public/hot
|
build
|
||||||
/public/storage
|
.svelte-kit
|
||||||
/storage/*.key
|
package
|
||||||
/vendor
|
|
||||||
.env
|
.env
|
||||||
.env.backup
|
.env.*
|
||||||
.env.secrets
|
!.env.example
|
||||||
.phpunit.result.cache
|
dist
|
||||||
Homestead.json
|
apps/api/db/*.db
|
||||||
Homestead.yaml
|
local-serve
|
||||||
auth.json
|
apps/api/db/migration.db-journal
|
||||||
npm-debug.log
|
apps/api/core*
|
||||||
yarn-error.log
|
logs
|
||||||
/.fleet
|
others/certificates
|
||||||
/.idea
|
|
||||||
/.vscode
|
|
||||||
/.npm
|
|
||||||
/.bash_history
|
|
||||||
/_data
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
indent_size = 4
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.md]
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
||||||
[*.{yml,yaml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[docker-compose.yml]
|
|
||||||
indent_size = 4
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
############################################################################################################
|
|
||||||
# Development Environment
|
|
||||||
|
|
||||||
# User and group id for the user that will run the application inside the container
|
|
||||||
# Run in your terminal: `id -u` and `id -g` and that's the results
|
|
||||||
USERID=
|
|
||||||
GROUPID=
|
|
||||||
############################################################################################################
|
|
||||||
APP_ID=development
|
|
||||||
APP_ENV=local
|
|
||||||
APP_KEY=
|
|
||||||
APP_DEBUG=true
|
|
||||||
APP_URL=http://localhost
|
|
||||||
APP_PORT=8000
|
|
||||||
|
|
||||||
DUSK_DRIVER_URL=http://selenium:4444
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
APP_ID=
|
|
||||||
APP_NAME=Coolify
|
|
||||||
APP_KEY=
|
|
||||||
|
|
||||||
DB_PASSWORD=
|
|
||||||
REDIS_PASSWORD=
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Secrets related to pushing to GH, Sync files to BunnyCDN etc. Only for maintainers.
|
|
||||||
# Not related to Coolify, but to how we publish new versions.
|
|
||||||
|
|
||||||
GITHUB_TOKEN=
|
|
||||||
BUNNY_API_KEY=
|
|
||||||
BUNNY_STORAGE_API_KEY=
|
|
||||||
11
.gitattributes
vendored
11
.gitattributes
vendored
@@ -1,11 +0,0 @@
|
|||||||
* text=auto eol=lf
|
|
||||||
|
|
||||||
*.blade.php diff=html
|
|
||||||
*.css diff=css
|
|
||||||
*.html diff=html
|
|
||||||
*.md diff=markdown
|
|
||||||
*.php diff=php
|
|
||||||
|
|
||||||
/.github export-ignore
|
|
||||||
CHANGELOG.md export-ignore
|
|
||||||
.styleci.yml export-ignore
|
|
||||||
2
.github/FUNDING.yaml → .github/FUNDING.yml
vendored
2
.github/FUNDING.yaml → .github/FUNDING.yml
vendored
@@ -1,2 +1,2 @@
|
|||||||
open_collective: coollabsio
|
open_collective: coollabsio
|
||||||
github: coollabsio
|
github: coollabsio
|
||||||
52
.github/ISSUE_TEMPLATE/--bug-report.yaml
vendored
Normal file
52
.github/ISSUE_TEMPLATE/--bug-report.yaml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: 🐞 Bug report
|
||||||
|
description: Create a bug report to help us improve coolify
|
||||||
|
title: "[Bug]: "
|
||||||
|
labels: [Bug]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to fill out this bug report! Please fill the form in English.
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Is there an existing issue for this?
|
||||||
|
options:
|
||||||
|
- label: I have searched the existing issues
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: repository
|
||||||
|
attributes:
|
||||||
|
label: Example public repository
|
||||||
|
description: "An example public git repository to reproduce the issue easily (if applicable)."
|
||||||
|
placeholder: "ex: https://github.com/coollabsio/coolify"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: A concise description of what you're experiencing and what you expect.
|
||||||
|
placeholder: |
|
||||||
|
When I do <X>, <Y> happens and I see the error message attached below:
|
||||||
|
```...```
|
||||||
|
What I expect is <Z>
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps To Reproduce
|
||||||
|
description: Add steps to reproduce this behaviour, include console / network logs & videos
|
||||||
|
placeholder: |
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Version
|
||||||
|
description: "The version of your coolify Instance"
|
||||||
|
placeholder: "2.5.2"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
28
.github/ISSUE_TEMPLATE/--feature-request.yaml
vendored
Normal file
28
.github/ISSUE_TEMPLATE/--feature-request.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: 🛠️ Feature request
|
||||||
|
description: Suggest an idea to improve coolify
|
||||||
|
title: '[Feature]: '
|
||||||
|
labels: [Enhancement]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to request a feature for coolify! Please also add your request here to get feedback from the community: https://feedback.coolify.io/!
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Is there an existing issue for this?
|
||||||
|
description: Please search to see if an issue related to this feature request already exists.
|
||||||
|
options:
|
||||||
|
- label: I have searched the existing issues
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Summary
|
||||||
|
description: One paragraph description of the feature.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Why should this be worked on?
|
||||||
|
description: A concise description of the problems or use cases for this feature request.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
20
.github/ISSUE_TEMPLATE/--task.yaml
vendored
Normal file
20
.github/ISSUE_TEMPLATE/--task.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
name: 📝 Task
|
||||||
|
description: Create a task for the team to work on
|
||||||
|
title: "[Task]: "
|
||||||
|
labels: [Task]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Is there an existing issue for this?
|
||||||
|
description: Please search to see if an issue related to this already exists.
|
||||||
|
options:
|
||||||
|
- label: I have searched the existing issues
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: SubTasks
|
||||||
|
placeholder: |
|
||||||
|
- Sub Task 1
|
||||||
|
- Sub Task 2
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: true
|
||||||
|
contact_links:
|
||||||
|
- name: 🤔 Questions and Help
|
||||||
|
url: https://discord.com/invite/6rDM4fkymF
|
||||||
|
about: Reach out to us on discord or our github discussions page.
|
||||||
|
- name: 🙋♂️ Service request
|
||||||
|
url: https://feedback.coolify.io/
|
||||||
|
about: Want to request a new service or build pack? For example Wordpress, Hasura, Appwrite, Angular etc...
|
||||||
80
.github/workflows/coolify-builder.yml
vendored
80
.github/workflows/coolify-builder.yml
vendored
@@ -1,80 +0,0 @@
|
|||||||
name: Coolify Builder (v4)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["main", "v4"]
|
|
||||||
paths:
|
|
||||||
- .github/workflows/coolify-builder.yml
|
|
||||||
- docker/coolify-builder/Dockerfile
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: "coollabsio/coolify-builder"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
amd64:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build image and push to registry
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
with:
|
|
||||||
no-cache: true
|
|
||||||
context: .
|
|
||||||
file: docker/coolify-builder/Dockerfile
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: true
|
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
|
||||||
aarch64:
|
|
||||||
runs-on: [self-hosted, arm64]
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build image and push to registry
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
with:
|
|
||||||
no-cache: true
|
|
||||||
context: .
|
|
||||||
file: docker/coolify-builder/Dockerfile
|
|
||||||
platforms: linux/aarch64
|
|
||||||
push: true
|
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:aarch64
|
|
||||||
merge-manifest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
needs: [amd64, aarch64]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Create & publish manifest
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
|
||||||
76
.github/workflows/development-build.yml
vendored
76
.github/workflows/development-build.yml
vendored
@@ -1,76 +0,0 @@
|
|||||||
name: Development Build (v4)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["next"]
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: "coollabsio/coolify"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
amd64:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build image and push to registry
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/prod-ssu/Dockerfile
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: true
|
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next
|
|
||||||
aarch64:
|
|
||||||
runs-on: [self-hosted, arm64]
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build image and push to registry
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/prod-ssu/Dockerfile
|
|
||||||
platforms: linux/aarch64
|
|
||||||
push: true
|
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next-aarch64
|
|
||||||
merge-manifest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
needs: [amd64, aarch64]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Create & publish manifest
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:next
|
|
||||||
- uses: sarisia/actions-status-discord@v1
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
|
|
||||||
44
.github/workflows/docker-image.yml
vendored
44
.github/workflows/docker-image.yml
vendored
@@ -1,44 +0,0 @@
|
|||||||
name: Docker Image CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
# push:
|
|
||||||
# branches: [ "main" ]
|
|
||||||
# pull_request:
|
|
||||||
# branches: [ "*" ]
|
|
||||||
push:
|
|
||||||
branches: ["this-does-not-exist"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["this-does-not-exist"]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Cache Docker layers
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
/usr/local/share/ca-certificates
|
|
||||||
/var/cache/apt/archives
|
|
||||||
/var/lib/apt/lists
|
|
||||||
~/.cache
|
|
||||||
key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-docker-
|
|
||||||
- name: Build the Docker image
|
|
||||||
run: |
|
|
||||||
cp .env.example .env
|
|
||||||
docker run --rm -u "$(id -u):$(id -g)" \
|
|
||||||
-v "$(pwd):/app" \
|
|
||||||
-w /app composer:2 \
|
|
||||||
composer install --ignore-platform-reqs
|
|
||||||
./vendor/bin/spin build
|
|
||||||
- name: Start the stack
|
|
||||||
run: |
|
|
||||||
./vendor/bin/spin up -d
|
|
||||||
./vendor/bin/spin exec coolify php artisan key:generate
|
|
||||||
./vendor/bin/spin exec coolify php artisan migrate:fresh --seed
|
|
||||||
- name: Test (missing E2E tests)
|
|
||||||
run: |
|
|
||||||
./vendor/bin/spin exec coolify php artisan test
|
|
||||||
85
.github/workflows/production-build.yml
vendored
85
.github/workflows/production-build.yml
vendored
@@ -1,85 +0,0 @@
|
|||||||
name: Production Build (v4)
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["main"]
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: "coollabsio/coolify"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
amd64:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Get Version
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT
|
|
||||||
- name: Build image and push to registry
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/prod-ssu/Dockerfile
|
|
||||||
platforms: linux/amd64
|
|
||||||
push: true
|
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
|
|
||||||
aarch64:
|
|
||||||
runs-on: [self-hosted, arm64]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Get Version
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT
|
|
||||||
- name: Build image and push to registry
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: docker/prod-ssu/Dockerfile
|
|
||||||
platforms: linux/aarch64
|
|
||||||
push: true
|
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
|
|
||||||
merge-manifest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
needs: [amd64, aarch64]
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
- name: Login to ghcr.io
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Get Version
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getVersion.php)"|xargs >> $GITHUB_OUTPUT
|
|
||||||
- name: Create & publish manifest
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
|
|
||||||
- uses: sarisia/actions-status-discord@v1
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}
|
|
||||||
105
.github/workflows/production-release.yml
vendored
Normal file
105
.github/workflows/production-release.yml
vendored
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
name: Production Release to ghcr.io
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [released]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAME: "coollabsio/coolify"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
amd64:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: "v3"
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: Login to ghcr.io
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Extract metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
aarch64:
|
||||||
|
runs-on: [self-hosted, arm64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: "v3"
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
- name: Login to ghcr.io
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Extract metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}-aarch64
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/aarch64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}-aarch64
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
merge-manifest:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [amd64, aarch64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: Login to ghcr.io
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Extract metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
- name: Create & publish manifest
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools create --append ${{ fromJSON(steps.meta.outputs.json).tags[0] }}-aarch64 --tag ${{ fromJSON(steps.meta.outputs.json).tags[0] }}
|
||||||
|
- uses: sarisia/actions-status-discord@v1
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}
|
||||||
98
.github/workflows/staging-release.yml
vendored
Normal file
98
.github/workflows/staging-release.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
name: Staging Release to ghcr.io
|
||||||
|
concurrency:
|
||||||
|
group: staging_environment
|
||||||
|
cancel-in-progress: true
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "v3"
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAME: "coollabsio/coolify"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
amd64:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: "v3"
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: Login to ghcr.io
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Extract metadata (tags, labels)
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
aarch64:
|
||||||
|
runs-on:
|
||||||
|
group: aarch-runners
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: "v3"
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: Login to ghcr.io
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Extract metadata (tags, labels)
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/aarch64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}-aarch64
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
merge-manifest:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [amd64, aarch64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: Login to ghcr.io
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Extract metadata (tags, labels)
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
- name: Create & publish manifest
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools create --append ${{ steps.meta.outputs.tags }}-aarch64 --tag ${{ steps.meta.outputs.tags }}
|
||||||
|
- uses: sarisia/actions-status-discord@v1
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
|
||||||
54
.gitignore
vendored
54
.gitignore
vendored
@@ -1,31 +1,25 @@
|
|||||||
/.phpunit.cache
|
.DS_Store
|
||||||
/node_modules
|
node_modules
|
||||||
/public/build
|
.pnpm-store
|
||||||
/public/hot
|
/apps/ui/build
|
||||||
/public/storage
|
/build
|
||||||
/storage/*.key
|
.svelte-kit
|
||||||
/vendor
|
package
|
||||||
.env
|
.env
|
||||||
.env.backup
|
.env.*
|
||||||
.env.secrets
|
!.env.example
|
||||||
.phpunit.result.cache
|
dist
|
||||||
Homestead.json
|
apps/api/db/*.db
|
||||||
Homestead.yaml
|
apps/api/db/migration.db-journal
|
||||||
auth.json
|
apps/api/core*
|
||||||
npm-debug.log
|
apps/server/build
|
||||||
yarn-error.log
|
apps/backup/backups/*
|
||||||
/.fleet
|
!apps/backup/backups/.gitkeep
|
||||||
/.idea
|
/logs
|
||||||
/.vscode
|
others/certificates
|
||||||
/.npm
|
backups/*
|
||||||
/.bash_history
|
!backups/.gitkeep
|
||||||
/_data
|
|
||||||
_testing_hosts/
|
# Trpc
|
||||||
_volumes/
|
apps/server/db/*.db
|
||||||
.lesshst
|
apps/server/db/*.db-journal
|
||||||
psysh_history
|
|
||||||
.psql_history
|
|
||||||
_ide_helper.php
|
|
||||||
.gitignore
|
|
||||||
.phpstorm.meta.php
|
|
||||||
_ide_helper_models.php
|
|
||||||
2
.gitpod.Dockerfile
vendored
Normal file
2
.gitpod.Dockerfile
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FROM gitpod/workspace-full:2022-08-17-18-37-55
|
||||||
|
RUN brew install buildpacks/tap/pack
|
||||||
71
.gitpod.yml
71
.gitpod.yml
@@ -1,65 +1,14 @@
|
|||||||
tasks:
|
# This configuration file was automatically generated by Gitpod.
|
||||||
- name: Setup Spin environment and Composer dependencies
|
# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
|
||||||
# Fix because of https://github.com/gitpod-io/gitpod/issues/16614
|
# and commit this file to your remote git repository to share the goodness with others.
|
||||||
before: sudo curl -o /usr/local/bin/docker-compose -fsSL https://github.com/docker/compose/releases/download/v2.16.0/docker-compose-linux-$(uname -m)
|
#image:
|
||||||
init: |
|
# file: .gitpod.Dockerfile
|
||||||
cp .env.example .env &&
|
#tasks:
|
||||||
sed -i "s#APP_URL=http://localhost#APP_URL=$(gp url 8000)#g" .env
|
# - init: pnpm install && pnpm db:push && pnpm db:seed
|
||||||
sed -i "s#USERID=#USERID=33333#g" .env
|
# command: pnpm dev
|
||||||
sed -i "s#GROUPID=#GROUPID=33333#g" .env
|
|
||||||
composer install --ignore-platform-reqs
|
|
||||||
./vendor/bin/spin up -d
|
|
||||||
./vendor/bin/spin exec -u webuser coolify php artisan key:generate
|
|
||||||
./vendor/bin/spin exec -u webuser coolify php artisan storage:link
|
|
||||||
./vendor/bin/spin exec -u webuser coolify php artisan migrate:fresh --seed
|
|
||||||
cat .coolify-logo
|
|
||||||
gp sync-done spin-is-ready
|
|
||||||
|
|
||||||
- name: Install Node dependencies and run Vite
|
|
||||||
command: |
|
|
||||||
echo "Waiting for Sail environment to boot up."
|
|
||||||
gp sync-await spin-is-ready
|
|
||||||
./vendor/bin/spin exec vite npm install
|
|
||||||
./vendor/bin/spin exec vite npm run dev
|
|
||||||
|
|
||||||
- name: Laravel Queue Worker, listening to code changes
|
|
||||||
command: |
|
|
||||||
echo "Waiting for Sail environment to boot up."
|
|
||||||
gp sync-await spin-is-ready
|
|
||||||
./vendor/bin/spin exec -u webuser coolify php artisan queue:listen
|
|
||||||
|
|
||||||
ports:
|
ports:
|
||||||
- port: 5432
|
- port: 3001
|
||||||
onOpen: ignore
|
|
||||||
name: PostgreSQL
|
|
||||||
visibility: public
|
visibility: public
|
||||||
- port: 5173
|
- port: 3000
|
||||||
onOpen: ignore
|
|
||||||
visibility: public
|
visibility: public
|
||||||
name: Node Server for Vite
|
|
||||||
- port: 8000
|
|
||||||
onOpen: ignore
|
|
||||||
visibility: public
|
|
||||||
name: Coolify
|
|
||||||
|
|
||||||
# Configure vscode
|
|
||||||
vscode:
|
|
||||||
extensions:
|
|
||||||
- bmewburn.vscode-intelephense-client
|
|
||||||
- ikappas.composer
|
|
||||||
- ms-azuretools.vscode-docker
|
|
||||||
- ecmel.vscode-html-css
|
|
||||||
- MehediDracula.php-namespace-resolver
|
|
||||||
- wmaurer.change-case
|
|
||||||
- Equinusocio.vsc-community-material-theme
|
|
||||||
- EditorConfig.EditorConfig
|
|
||||||
- streetsidesoftware.code-spell-checker
|
|
||||||
- rangav.vscode-thunder-client
|
|
||||||
- PKief.material-icon-theme
|
|
||||||
- cierra.livewire-vscode
|
|
||||||
- lennardv.livewire-goto-updated
|
|
||||||
- bradlc.vscode-tailwindcss
|
|
||||||
- heybourn.headwind
|
|
||||||
- adrianwilczynski.alpine-js-intellisense
|
|
||||||
- amiralizadeh9480.laravel-extra-intellisense
|
|
||||||
- shufo.vscode-blade-formatter
|
|
||||||
|
|||||||
31
.vscode/settings.json
vendored
Normal file
31
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"i18n-ally.localesPaths": [
|
||||||
|
"src/lib/locales"
|
||||||
|
],
|
||||||
|
"i18n-ally.keystyle": "nested",
|
||||||
|
"i18n-ally.extract.ignoredByFiles": {
|
||||||
|
"src\\routes\\__layout.svelte": [
|
||||||
|
"Coolify",
|
||||||
|
"coolLabs logo"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"i18n-ally.sourceLanguage": "en",
|
||||||
|
"i18n-ally.enabledFrameworks": [
|
||||||
|
"svelte"
|
||||||
|
],
|
||||||
|
"i18n-ally.enabledParsers": [
|
||||||
|
"js",
|
||||||
|
"ts",
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"i18n-ally.extract.autoDetect": true,
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.git": true,
|
||||||
|
"**/.svn": true,
|
||||||
|
"**/.hg": true,
|
||||||
|
"**/CVS": true,
|
||||||
|
"**/.DS_Store": true,
|
||||||
|
"**/Thumbs.db": true
|
||||||
|
},
|
||||||
|
"hide-files.files": []
|
||||||
|
}
|
||||||
48
CONTRIBUTION.md
Normal file
48
CONTRIBUTION.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
> "First, thanks for considering to contribute to my project.
|
||||||
|
It really means a lot! 😁" - [@andrasbacsai](https://github.com/andrasbacsai)
|
||||||
|
|
||||||
|
You can ask for guidance anytime on our
|
||||||
|
[Discord server](https://coollabs.io/discord) in the `#contribution` channel.
|
||||||
|
|
||||||
|
You'll need a set of skills to [get started](docs/contribution/GettingStarted.md).
|
||||||
|
|
||||||
|
## 1) Setup your development environment
|
||||||
|
|
||||||
|
- 🌟 [Container based](docs/dev_setup/Container.md) ← *Recommended*
|
||||||
|
- 📦 [DockerContainer](docs/dev_setup/DockerContiner.md) *WIP
|
||||||
|
- 🐙 [Github Codespaces](docs/dev_setup/GithubCodespaces.md)
|
||||||
|
- ☁️ [GitPod](docs/dev_setup/GitPod.md)
|
||||||
|
- 🍏 [Local Mac](docs/dev_setup/Mac.md)
|
||||||
|
|
||||||
|
## 2) Basic requirements
|
||||||
|
|
||||||
|
- [Install Pnpm](https://pnpm.io/installation)
|
||||||
|
- [Install Docker Engine](https://docs.docker.com/engine/install/)
|
||||||
|
- [Setup Docker Compose Plugin](https://docs.docker.com/compose/install/)
|
||||||
|
- [Setup GIT LFS Support](https://git-lfs.github.com/)
|
||||||
|
|
||||||
|
## 3) Setup Coolify
|
||||||
|
|
||||||
|
- Copy `apps/api/.env.example` to `apps/api/.env`
|
||||||
|
- Edit `apps/api/.env`, set the `COOLIFY_APP_ID` environment variable to something cool.
|
||||||
|
- Run `pnpm install` to install dependencies.
|
||||||
|
- Run `pnpm db:push` to create a local SQlite database. This will apply all migrations at `db/dev.db`.
|
||||||
|
- Run `pnpm db:seed` seed the database.
|
||||||
|
- Run `pnpm dev` start coding.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Or... Copy and paste commands below:
|
||||||
|
cp apps/api/.env.example apps/api/.env
|
||||||
|
pnpm install
|
||||||
|
pnpm db:push
|
||||||
|
pnpm db:seed
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4) Start Coding
|
||||||
|
|
||||||
|
You should be able to access `http://localhost:3000`.
|
||||||
|
|
||||||
|
1. Click `Register` and setup your first user.
|
||||||
53
Dockerfile
Normal file
53
Dockerfile
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
ARG PNPM_VERSION=7.11.0
|
||||||
|
|
||||||
|
FROM node:18-slim as build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt update && apt -y install curl
|
||||||
|
RUN npm --no-update-notifier --no-fund --global install pnpm@${PNPM_VERSION}
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN pnpm install
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# Production build
|
||||||
|
FROM node:18-slim
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV production
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
|
# https://download.docker.com/linux/static/stable/
|
||||||
|
ARG DOCKER_VERSION=20.10.18
|
||||||
|
# https://github.com/docker/compose/releases
|
||||||
|
# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug.
|
||||||
|
ARG DOCKER_COMPOSE_VERSION=2.6.1
|
||||||
|
# https://github.com/buildpacks/pack/releases
|
||||||
|
ARG PACK_VERSION=0.27.0
|
||||||
|
|
||||||
|
RUN apt update && apt -y install --no-install-recommends ca-certificates git git-lfs openssh-client curl jq cmake sqlite3 openssl psmisc python3 vim
|
||||||
|
RUN apt-get clean autoclean && apt-get autoremove --yes && rm -rf /var/lib/{apt,dpkg,cache,log}/
|
||||||
|
RUN npm --no-update-notifier --no-fund --global install pnpm@${PNPM_VERSION}
|
||||||
|
RUN npm install -g npm@${PNPM_VERSION}
|
||||||
|
|
||||||
|
RUN mkdir -p ~/.docker/cli-plugins/
|
||||||
|
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack
|
||||||
|
|
||||||
|
RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack
|
||||||
|
|
||||||
|
COPY --from=build /app/apps/api/build/ .
|
||||||
|
# COPY --from=build /app/others/fluentbit/ ./fluentbit
|
||||||
|
COPY --from=build /app/apps/ui/build/ ./public
|
||||||
|
COPY --from=build /app/apps/api/prisma/ ./prisma
|
||||||
|
COPY --from=build /app/apps/api/package.json .
|
||||||
|
COPY --from=build /app/docker-compose.yaml .
|
||||||
|
COPY --from=build /app/apps/api/tags.json .
|
||||||
|
COPY --from=build /app/apps/api/templates.json .
|
||||||
|
|
||||||
|
RUN pnpm install -p
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
ENV CHECKPOINT_DISABLE=1
|
||||||
|
CMD pnpm start
|
||||||
31
Dockerfile-dev
Normal file
31
Dockerfile-dev
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
FROM node:18-slim
|
||||||
|
ENV NODE_ENV development
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
ARG PNPM_VERSION=7.11.0
|
||||||
|
ARG NPM_VERSION=8.19.1
|
||||||
|
# https://download.docker.com/linux/static/stable/
|
||||||
|
ARG DOCKER_VERSION=20.10.18
|
||||||
|
# https://github.com/docker/compose/releases
|
||||||
|
# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug.
|
||||||
|
ARG DOCKER_COMPOSE_VERSION=2.6.1
|
||||||
|
# https://github.com/buildpacks/pack/releases
|
||||||
|
ARG PACK_VERSION=0.27.0
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN npm --no-update-notifier --no-fund --global install pnpm@${PNPM_VERSION}
|
||||||
|
|
||||||
|
RUN apt update && apt -y install --no-install-recommends ca-certificates git git-lfs openssh-client curl jq cmake sqlite3 openssl psmisc python3
|
||||||
|
RUN apt-get clean autoclean && apt-get autoremove --yes && rm -rf /var/lib/{apt,dpkg,cache,log}/
|
||||||
|
RUN npm --no-update-notifier --no-fund --global install pnpm@${PNPM_VERSION}
|
||||||
|
RUN npm install -g npm@${PNPM_VERSION}
|
||||||
|
|
||||||
|
RUN mkdir -p ~/.docker/cli-plugins/
|
||||||
|
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack
|
||||||
|
|
||||||
|
RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
ENV CHECKPOINT_DISABLE=1
|
||||||
133
README.md
133
README.md
@@ -1,36 +1,128 @@
|
|||||||
# Coolify v4 Beta
|
# Coolify
|
||||||
|
|
||||||
An open-source & self-hostable Heroku / Netlify alternative.
|
An open-source & self-hostable Heroku / Netlify alternative.
|
||||||
|
|
||||||
# Beta
|
## Live Demo
|
||||||
|
|
||||||
You are checking the next-gen of Coolify, aka v4. Hi 👋
|
https://demo.coolify.io/
|
||||||
|
|
||||||
It is still in beta, lots of improvements will come every day. Things could break, but we are working hard to make it stable as soon as possible. If you find any bugs, please report them.
|
(If it is unresponsive, that means someone overloaded the server. 😄)
|
||||||
|
|
||||||
Automatic updates are available, so you will receive the latest version as soon as it is released.
|
## Feedback
|
||||||
|
|
||||||
If you are looking for v3, check out the [v3 branch](https://github.com/coollabsio/coolify/tree/v3).
|
If you have a new service / build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
|
||||||
|
|
||||||
## What's new?
|
---
|
||||||
|
|
||||||
Well, the whole tech stack changed, core is different, so yeah, a lot (documentation incoming).
|
## How to install
|
||||||
|
|
||||||
# Installation
|
For more details goto the [docs](https://docs.coollabs.io/coolify-v3/installation).
|
||||||
|
|
||||||
|
Installation is automated with the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
You can find the installation script [here](./scripts/install.sh).
|
If you would like no questions during installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh -f
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Git Sources
|
||||||
|
|
||||||
|
Self-hosted versions also!
|
||||||
|
|
||||||
|
<a href="https://github.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/github.com"></a>
|
||||||
|
<a href="https://gitlab.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/gitlab.com"></a>
|
||||||
|
|
||||||
|
### Destinations
|
||||||
|
|
||||||
|
Deploy your resource to:
|
||||||
|
|
||||||
|
- Local Docker Engine
|
||||||
|
- Remote Docker Engine
|
||||||
|
|
||||||
|
### Applications
|
||||||
|
|
||||||
|
<a href="https://heroku.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/heroku.com"></a>
|
||||||
|
<a href="https://html5.org/">
|
||||||
|
<svg style="width:40px;height:40px" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" ><g clip-path="url(#HTML5_Clip0_4)" ><path d="M30.216 0L27.6454 28.7967L16.0907 32L4.56783 28.8012L2 0H30.216Z" fill="#E44D26" /><path d="M16.108 29.5515L25.4447 26.963L27.6415 2.35497H16.108V29.5515Z" fill="#F16529" /><path d="M11.1109 9.4197H16.108V5.88731H7.25053L7.33509 6.83499L8.20327 16.5692H16.108V13.0369H11.4338L11.1109 9.4197Z" fill="#EBEBEB" /><path d="M11.907 18.3354H8.36111L8.856 23.8818L16.0917 25.8904L16.108 25.8859V22.2108L16.0925 22.2149L12.1585 21.1527L11.907 18.3354Z" fill="#EBEBEB" /><path d="M16.0958 16.5692H20.4455L20.0354 21.1504L16.0958 22.2138V25.8887L23.3373 23.8817L23.3904 23.285L24.2205 13.9855L24.3067 13.0369H16.0958V16.5692Z" fill="white" /><path d="M16.0958 9.41105V9.41969H24.6281L24.6989 8.62572L24.8599 6.83499L24.9444 5.88731H16.0958V9.41105Z" fill="white" /></g><defs><clipPath id="HTML5_Clip0_4"><rect width="32" height="32" fill="white" /></clipPath></defs></svg></a>
|
||||||
|
<a href="https://nodejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nodejs.org"></a>
|
||||||
|
<a href="https://vuejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/vuejs.org"></a>
|
||||||
|
<a href="https://nuxtjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nuxtjs.org"></a>
|
||||||
|
<a href="https://nextjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nextjs.org"></a>
|
||||||
|
<a href="https://reactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/reactjs.org"></a>
|
||||||
|
<a href="https://preactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/preactjs.org"></a>
|
||||||
|
<a href="https://gatsbyjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/gatsbyjs.org"></a>
|
||||||
|
<a href="https://svelte.dev"><img style="width:40px;height:40px" src="https://icon.horse/icon/svelte.dev"></a>
|
||||||
|
<a href="https://php.net"><img style="width:40px;height:40px" src="https://icon.horse/icon/php.net"></a>
|
||||||
|
<a href="https://laravel.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/laravel.com"></a>
|
||||||
|
<a href="https://python.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/python.org"></a>
|
||||||
|
<a href="https://deno.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/deno.com"></a>
|
||||||
|
<a href="https://docker.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/docker.com"></a>
|
||||||
|
|
||||||
|
### Databases
|
||||||
|
|
||||||
|
<a href="https://mongodb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mongodb.org"></a>
|
||||||
|
<a href="https://mariadb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mariadb.org"></a>
|
||||||
|
<a href="https://mysql.com"><svg style="width:40px;height:40px" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 25.6 25.6" ><path d="M179.076 94.886c-3.568-.1-6.336.268-8.656 1.25-.668.27-1.74.27-1.828 1.116.357.355.4.936.713 1.428.535.893 1.473 2.096 2.32 2.72l2.855 2.053c1.74 1.07 3.703 1.695 5.398 2.766.982.625 1.963 1.428 2.945 2.098.5.357.803.938 1.428 1.16v-.135c-.312-.4-.402-.98-.713-1.428l-1.34-1.293c-1.293-1.74-2.9-3.258-4.64-4.506-1.428-.982-4.55-2.32-5.13-3.97l-.088-.1c.98-.1 2.14-.447 3.078-.715 1.518-.4 2.9-.312 4.46-.713l2.143-.625v-.4c-.803-.803-1.383-1.874-2.23-2.632-2.275-1.963-4.775-3.882-7.363-5.488-1.383-.892-3.168-1.473-4.64-2.23-.537-.268-1.428-.402-1.74-.848-.805-.98-1.25-2.275-1.83-3.436l-3.658-7.763c-.803-1.74-1.295-3.48-2.275-5.086-4.596-7.585-9.594-12.18-17.268-16.687-1.65-.937-3.613-1.34-5.7-1.83l-3.346-.18c-.715-.312-1.428-1.16-2.053-1.562-2.543-1.606-9.102-5.086-10.977-.5-1.205 2.9 1.785 5.755 2.8 7.228.76 1.026 1.74 2.186 2.277 3.346.3.758.4 1.562.713 2.365.713 1.963 1.383 4.15 2.32 5.98.5.937 1.025 1.92 1.65 2.767.357.5.982.714 1.115 1.517-.625.893-.668 2.23-1.025 3.347-1.607 5.042-.982 11.288 1.293 15 .715 1.115 2.4 3.57 4.686 2.632 2.008-.803 1.56-3.346 2.14-5.577.135-.535.045-.892.312-1.25v.1l1.83 3.703c1.383 2.186 3.793 4.462 5.8 5.98 1.07.803 1.918 2.187 3.256 2.677v-.135h-.088c-.268-.4-.67-.58-1.027-.892-.803-.803-1.695-1.785-2.32-2.677-1.873-2.498-3.523-5.265-4.996-8.12-.715-1.383-1.34-2.9-1.918-4.283-.27-.536-.27-1.34-.715-1.606-.67.98-1.65 1.83-2.143 3.034-.848 1.918-.936 4.283-1.248 6.737-.18.045-.1 0-.18.1-1.426-.356-1.918-1.83-2.453-3.078-1.338-3.168-1.562-8.254-.402-11.913.312-.937 1.652-3.882 1.117-4.774-.27-.848-1.16-1.338-1.652-2.008-.58-.848-1.203-1.918-1.605-2.855-1.07-2.5-1.605-5.265-2.766-7.764-.537-1.16-1.473-2.365-2.232-3.435-.848-1.205-1.783-2.053-2.453-3.48-.223-.5-.535-1.294-.178-1.83.088-.357.268-.5.623-.58.58-.5 2.232.134 2.812.4 1.65.67 3.033 1.294 4.416 2.23.625.446 1.295 1.294 2.098 1.518h.938c1.428.312 3.033.1 4.37.5 2.365.76 4.506 1.874 6.426 3.08 5.844 3.703 10.664 8.968 13.92 15.26.535 1.026.758 1.963 1.25 3.034.938 2.187 2.098 4.417 3.033 6.56.938 2.097 1.83 4.24 3.168 5.98.67.937 3.346 1.427 4.55 1.918.893.4 2.275.76 3.08 1.25 1.516.937 3.033 2.008 4.46 3.034.713.534 2.945 1.65 3.078 2.54zm-45.5-38.772a7.09 7.09 0 0 0-1.828.223v.1h.088c.357.714.982 1.205 1.428 1.83l1.027 2.142.088-.1c.625-.446.938-1.16.938-2.23-.268-.312-.312-.625-.535-.937-.268-.446-.848-.67-1.206-1.026z" transform="matrix(.390229 0 0 .38781 -46.300037 -16.856717)" fill-rule="evenodd" fill="#00678c" /></svg></a>
|
||||||
|
<a href="https://postgresql.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/postgresql.org"></a>
|
||||||
|
<a href="https://couchdb.apache.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/couchdb.apache.org"></a>
|
||||||
|
<a href="https://redis.io"><svg style="width:40px;height:40px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><defs ><path id="a" d="m45.536 38.764c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.813s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" /><path id="b" d="m45.536 28.733c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.935c2.332-.837 3.14-.867 5.126-.14s12.35 4.853 14.312 5.57 2.037 1.31.024 2.36z" /></defs ><g transform="matrix(.848327 0 0 .848327 -7.883573 -9.449691)" ><use fill="#a41e11" xlink:href="#a" /><path d="m45.536 34.95c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.936c2.332-.836 3.14-.867 5.126-.14s12.35 4.852 14.31 5.582 2.037 1.31.024 2.36z" fill="#d82c20" /><use fill="#a41e11" xlink:href="#a" y="-6.218" /><use fill="#d82c20" xlink:href="#b" /><path d="m45.536 26.098c-2.013 1.05-12.44 5.337-14.66 6.495s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.815s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" fill="#a41e11" /><use fill="#d82c20" xlink:href="#b" y="-6.449" /><g fill="#fff" ><path d="m29.096 20.712-1.182-1.965-3.774-.34 2.816-1.016-.845-1.56 2.636 1.03 2.486-.814-.672 1.612 2.534.95-3.268.34zm-6.296 3.912 8.74-1.342-2.64 3.872z" /><ellipse cx="20.444" cy="21.402" rx="4.672" ry="1.811" /></g ><path d="m42.132 21.138-5.17 2.042-.004-4.087z" fill="#7a0c00" /><path d="m36.963 23.18-.56.22-5.166-2.042 5.723-2.264z" fill="#ad2115" /></g ></svg ></a>
|
||||||
|
|
||||||
|
### Services
|
||||||
|
|
||||||
|
- [Appwrite](https://appwrite.io)
|
||||||
|
- [WordPress](https://docs.coollabs.io/coolify-v3/services/wordpress)
|
||||||
|
- [Ghost](https://ghost.org)
|
||||||
|
- [Plausible Analytics](https://docs.coollabs.io/coolify-v3/services/plausible-analytics)
|
||||||
|
- [NocoDB](https://nocodb.com)
|
||||||
|
- [VSCode Server](https://github.com/cdr/code-server)
|
||||||
|
- [MinIO](https://min.io)
|
||||||
|
- [VaultWarden](https://github.com/dani-garcia/vaultwarden)
|
||||||
|
- [LanguageTool](https://languagetool.org)
|
||||||
|
- [n8n](https://n8n.io)
|
||||||
|
- [Uptime Kuma](https://github.com/louislam/uptime-kuma)
|
||||||
|
- [MeiliSearch](https://github.com/meilisearch/meilisearch)
|
||||||
|
- [Umami](https://github.com/mikecao/umami)
|
||||||
|
- [Fider](https://fider.io)
|
||||||
|
- [Hasura](https://hasura.io)
|
||||||
|
- [GlitchTip](https://glitchtip.com)
|
||||||
|
- And more...
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
- Twitter: [@heyandras](https://twitter.com/heyandras)
|
- Mastodon: [@andrasbacsai@fosstodon.org](https://fosstodon.org/@andrasbacsai)
|
||||||
- Mastodon: [@andrasbacsai@fosstodon.org](https://fosstodon.org/@andrasbacsai)
|
- Telegram: [@andrasbacsai](https://t.me/andrasbacsai)
|
||||||
- Email: [andras@coollabs.io](mailto:andras@coollabs.io)
|
- Twitter: [@andrasbacsai](https://twitter.com/heyandras)
|
||||||
- Discord: [Invitation](https://coollabs.io/discord)
|
- Email: [andras@coollabs.io](mailto:andras@coollabs.io)
|
||||||
- Telegram: [@andrasbacsai](https://t.me/andrasbacsai)
|
- Discord: [Invitation](https://coollabs.io/discord)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚗️ Expertise Contributions
|
||||||
|
|
||||||
|
Coolify is developed under the [Apache License](./LICENSE) and you can help to make it grow.
|
||||||
|
Our community will be glad to have you on board!
|
||||||
|
|
||||||
|
Learn how to contribute to Coolify as as ...
|
||||||
|
|
||||||
|
→ [👩🏾💻 Software developer](./CONTRIBUTION.md)
|
||||||
|
|
||||||
|
→ [🧑🏻🏫 Translator](./docs/contribution/Translating.md)
|
||||||
|
|
||||||
|
<!--
|
||||||
|
→ 🧑🏽🎨 Designer
|
||||||
|
→ 🙋♀️ Community Manager
|
||||||
|
→ 🧙🏻♂️ Text Content Creator
|
||||||
|
→ 👨🏼🎤 Video Content Creator
|
||||||
|
-->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -40,12 +132,11 @@ Become a financial contributor and help us sustain our community. [[Contribute](
|
|||||||
|
|
||||||
### Organizations
|
### Organizations
|
||||||
|
|
||||||
Special thanks to our biggest sponsors, [CCCareers](https://cccareers.org/) and [Appwrite](https://appwrite.io)!
|
Special thanks to our biggest sponsor, [CCCareers](https://cccareers.org/)!
|
||||||
|
|
||||||
<a href="https://cccareers.org/" target="_blank"><img src="./other/logos/ccc-logo.webp" alt="appwrite logo" width="200"/></a>
|

|
||||||
<a href="https://appwrite.io" target="_blank"><img src="./other/logos/appwrite.svg" alt="appwrite logo" width="200"/></a>
|
|
||||||
|
|
||||||
Support this project with your organization. Your logo will show up here with a link to your website.
|
Support this project with your organization. Your logo will show up here with a link to your website.
|
||||||
|
|
||||||
<a href="https://opencollective.com/coollabsio/organization/0/website"><img src="https://opencollective.com/coollabsio/organization/0/avatar.svg"></a>
|
<a href="https://opencollective.com/coollabsio/organization/0/website"><img src="https://opencollective.com/coollabsio/organization/0/avatar.svg"></a>
|
||||||
<a href="https://opencollective.com/coollabsio/organization/1/website"><img src="https://opencollective.com/coollabsio/organization/1/avatar.svg"></a>
|
<a href="https://opencollective.com/coollabsio/organization/1/website"><img src="https://opencollective.com/coollabsio/organization/1/avatar.svg"></a>
|
||||||
@@ -56,7 +147,7 @@ Support this project with your organization. Your logo will show up here with a
|
|||||||
<a href="https://opencollective.com/coollabsio/organization/6/website"><img src="https://opencollective.com/coollabsio/organization/6/avatar.svg"></a>
|
<a href="https://opencollective.com/coollabsio/organization/6/website"><img src="https://opencollective.com/coollabsio/organization/6/avatar.svg"></a>
|
||||||
<a href="https://opencollective.com/coollabsio/organization/7/website"><img src="https://opencollective.com/coollabsio/organization/7/avatar.svg"></a>
|
<a href="https://opencollective.com/coollabsio/organization/7/website"><img src="https://opencollective.com/coollabsio/organization/7/avatar.svg"></a>
|
||||||
<a href="https://opencollective.com/coollabsio/organization/8/website"><img src="https://opencollective.com/coollabsio/organization/8/avatar.svg"></a>
|
<a href="https://opencollective.com/coollabsio/organization/8/website"><img src="https://opencollective.com/coollabsio/organization/8/avatar.svg"></a>
|
||||||
<a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a>
|
<a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a>
|
||||||
|
|
||||||
### Individuals
|
### Individuals
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\CoolifyTask;
|
|
||||||
|
|
||||||
use App\Data\CoolifyTaskArgs;
|
|
||||||
use App\Jobs\CoolifyTask;
|
|
||||||
use Spatie\Activitylog\Models\Activity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The initial step to run a `CoolifyTask`: a remote SSH process
|
|
||||||
* with monitoring/tracking/trace feature. Such thing is made
|
|
||||||
* possible using an Activity model and some attributes.
|
|
||||||
*/
|
|
||||||
class PrepareCoolifyTask
|
|
||||||
{
|
|
||||||
protected Activity $activity;
|
|
||||||
protected CoolifyTaskArgs $remoteProcessArgs;
|
|
||||||
public function __construct(CoolifyTaskArgs $remoteProcessArgs)
|
|
||||||
{
|
|
||||||
$this->remoteProcessArgs = $remoteProcessArgs;
|
|
||||||
|
|
||||||
if ($remoteProcessArgs->model) {
|
|
||||||
$properties = $remoteProcessArgs->toArray();
|
|
||||||
unset($properties['model']);
|
|
||||||
|
|
||||||
$this->activity = activity()
|
|
||||||
->withProperties($properties)
|
|
||||||
->performedOn($remoteProcessArgs->model)
|
|
||||||
->event($remoteProcessArgs->type)
|
|
||||||
->log("[]");
|
|
||||||
} else {
|
|
||||||
$this->activity = activity()
|
|
||||||
->withProperties($remoteProcessArgs->toArray())
|
|
||||||
->event($remoteProcessArgs->type)
|
|
||||||
->log("[]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __invoke(): Activity
|
|
||||||
{
|
|
||||||
$job = new CoolifyTask($this->activity, ignore_errors: $this->remoteProcessArgs->ignore_errors);
|
|
||||||
dispatch($job);
|
|
||||||
$this->activity->refresh();
|
|
||||||
return $this->activity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\CoolifyTask;
|
|
||||||
|
|
||||||
use App\Enums\ActivityTypes;
|
|
||||||
use App\Enums\ProcessStatus;
|
|
||||||
use App\Jobs\ApplicationDeploymentJob;
|
|
||||||
use Illuminate\Process\ProcessResult;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Process;
|
|
||||||
use Spatie\Activitylog\Models\Activity;
|
|
||||||
|
|
||||||
const TIMEOUT = 3600;
|
|
||||||
const IDLE_TIMEOUT = 3600;
|
|
||||||
|
|
||||||
class RunRemoteProcess
|
|
||||||
{
|
|
||||||
public Activity $activity;
|
|
||||||
|
|
||||||
public bool $hide_from_output;
|
|
||||||
|
|
||||||
public bool $is_finished;
|
|
||||||
|
|
||||||
public bool $ignore_errors;
|
|
||||||
|
|
||||||
protected $time_start;
|
|
||||||
|
|
||||||
protected $current_time;
|
|
||||||
|
|
||||||
protected $last_write_at = 0;
|
|
||||||
|
|
||||||
protected $throttle_interval_ms = 500;
|
|
||||||
|
|
||||||
protected int $counter = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new job instance.
|
|
||||||
*/
|
|
||||||
public function __construct(Activity $activity, bool $hide_from_output = false, bool $is_finished = false, bool $ignore_errors = false)
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value) {
|
|
||||||
throw new \RuntimeException('Incompatible Activity to run a remote command.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->activity = $activity;
|
|
||||||
$this->hide_from_output = $hide_from_output;
|
|
||||||
$this->is_finished = $is_finished;
|
|
||||||
$this->ignore_errors = $ignore_errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __invoke(): ProcessResult
|
|
||||||
{
|
|
||||||
$this->time_start = hrtime(true);
|
|
||||||
|
|
||||||
$status = ProcessStatus::IN_PROGRESS;
|
|
||||||
|
|
||||||
$processResult = Process::timeout(TIMEOUT)->idleTimeout(IDLE_TIMEOUT)->run($this->getCommand(), $this->handleOutput(...));
|
|
||||||
|
|
||||||
if ($this->activity->properties->get('status') === ProcessStatus::ERROR->value) {
|
|
||||||
$status = ProcessStatus::ERROR;
|
|
||||||
} else {
|
|
||||||
if (($processResult->exitCode() == 0 && $this->is_finished) || $this->activity->properties->get('status') === ProcessStatus::FINISHED->value) {
|
|
||||||
$status = ProcessStatus::FINISHED;
|
|
||||||
}
|
|
||||||
if ($processResult->exitCode() != 0 && !$this->ignore_errors) {
|
|
||||||
$status = ProcessStatus::ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->activity->properties = $this->activity->properties->merge([
|
|
||||||
'exitCode' => $processResult->exitCode(),
|
|
||||||
'stdout' => $processResult->output(),
|
|
||||||
'stderr' => $processResult->errorOutput(),
|
|
||||||
'status' => $status->value,
|
|
||||||
]);
|
|
||||||
$this->activity->save();
|
|
||||||
|
|
||||||
if ($processResult->exitCode() != 0 && !$this->ignore_errors) {
|
|
||||||
throw new \RuntimeException($processResult->errorOutput());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $processResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getLatestCounter(): int
|
|
||||||
{
|
|
||||||
$description = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
|
|
||||||
if ($description === null || count($description) === 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return end($description)['order'] + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getCommand(): string
|
|
||||||
{
|
|
||||||
$user = $this->activity->getExtraProperty('user');
|
|
||||||
$server_ip = $this->activity->getExtraProperty('server_ip');
|
|
||||||
$private_key_location = $this->activity->getExtraProperty('private_key_location');
|
|
||||||
$port = $this->activity->getExtraProperty('port');
|
|
||||||
$command = $this->activity->getExtraProperty('command');
|
|
||||||
|
|
||||||
return generate_ssh_command($private_key_location, $server_ip, $user, $port, $command);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function handleOutput(string $type, string $output)
|
|
||||||
{
|
|
||||||
if ($this->hide_from_output) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->current_time = $this->elapsedTime();
|
|
||||||
$this->activity->description = $this->encodeOutput($type, $output);
|
|
||||||
|
|
||||||
if ($this->isAfterLastThrottle()) {
|
|
||||||
// Let's write to database.
|
|
||||||
DB::transaction(function () {
|
|
||||||
$this->activity->save();
|
|
||||||
$this->last_write_at = $this->current_time;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function encodeOutput($type, $output)
|
|
||||||
{
|
|
||||||
$outputStack = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
|
|
||||||
|
|
||||||
$outputStack[] = [
|
|
||||||
'type' => $type,
|
|
||||||
'output' => $output,
|
|
||||||
'timestamp' => hrtime(true),
|
|
||||||
'batch' => ApplicationDeploymentJob::$batch_counter,
|
|
||||||
'order' => $this->getLatestCounter(),
|
|
||||||
];
|
|
||||||
|
|
||||||
return json_encode($outputStack, flags: JSON_THROW_ON_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function decodeOutput(?Activity $activity = null): string
|
|
||||||
{
|
|
||||||
if (is_null($activity)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$decoded = json_decode(
|
|
||||||
data_get($activity, 'description'),
|
|
||||||
associative: true,
|
|
||||||
flags: JSON_THROW_ON_ERROR
|
|
||||||
);
|
|
||||||
} catch (\JsonException $exception) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return collect($decoded)
|
|
||||||
->sortBy(fn ($i) => $i['order'])
|
|
||||||
->map(fn ($i) => $i['output'])
|
|
||||||
->implode("");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if it's time to write again to database.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected function isAfterLastThrottle()
|
|
||||||
{
|
|
||||||
// If DB was never written, then we immediately decide we have to write.
|
|
||||||
if ($this->last_write_at === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ($this->current_time - $this->throttle_interval_ms) > $this->last_write_at;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function elapsedTime(): int
|
|
||||||
{
|
|
||||||
$timeMs = (hrtime(true) - $this->time_start) / 1_000_000;
|
|
||||||
|
|
||||||
return intval($timeMs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Fortify;
|
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
|
||||||
use App\Models\Team;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
use Laravel\Fortify\Contracts\CreatesNewUsers;
|
|
||||||
|
|
||||||
class CreateNewUser implements CreatesNewUsers
|
|
||||||
{
|
|
||||||
use PasswordValidationRules;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate and create a newly registered user.
|
|
||||||
*
|
|
||||||
* @param array<string, string> $input
|
|
||||||
*/
|
|
||||||
public function create(array $input): User
|
|
||||||
{
|
|
||||||
$settings = InstanceSettings::get();
|
|
||||||
if (!$settings->is_registration_enabled) {
|
|
||||||
Log::info('Registration is disabled');
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
Validator::make($input, [
|
|
||||||
'name' => ['required', 'string', 'max:255'],
|
|
||||||
'email' => [
|
|
||||||
'required',
|
|
||||||
'string',
|
|
||||||
'email',
|
|
||||||
'max:255',
|
|
||||||
Rule::unique(User::class),
|
|
||||||
],
|
|
||||||
'password' => $this->passwordRules(),
|
|
||||||
])->validate();
|
|
||||||
|
|
||||||
if (User::count() == 0) {
|
|
||||||
// If this is the first user, make them the root user
|
|
||||||
// Team is already created in the database/seeders/ProductionSeeder.php
|
|
||||||
$user = User::create([
|
|
||||||
'id' => 0,
|
|
||||||
'name' => $input['name'],
|
|
||||||
'email' => $input['email'],
|
|
||||||
'password' => Hash::make($input['password']),
|
|
||||||
]);
|
|
||||||
$team = $user->teams()->first();
|
|
||||||
|
|
||||||
// Disable registration after first user is created
|
|
||||||
$settings = InstanceSettings::get();
|
|
||||||
$settings->is_registration_enabled = false;
|
|
||||||
$settings->save();
|
|
||||||
} else {
|
|
||||||
$user = User::create([
|
|
||||||
'name' => $input['name'],
|
|
||||||
'email' => $input['email'],
|
|
||||||
'password' => Hash::make($input['password']),
|
|
||||||
]);
|
|
||||||
$team = $user->teams()->first();
|
|
||||||
}
|
|
||||||
// Set session variable
|
|
||||||
session(['currentTeam' => $user->currentTeam = $team]);
|
|
||||||
return $user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Fortify;
|
|
||||||
|
|
||||||
use Laravel\Fortify\Rules\Password;
|
|
||||||
|
|
||||||
trait PasswordValidationRules
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the validation rules used to validate passwords.
|
|
||||||
*
|
|
||||||
* @return array<int, \Illuminate\Contracts\Validation\Rule|array|string>
|
|
||||||
*/
|
|
||||||
protected function passwordRules(): array
|
|
||||||
{
|
|
||||||
return ['required', 'string', new Password, 'confirmed'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Fortify;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Laravel\Fortify\Contracts\ResetsUserPasswords;
|
|
||||||
|
|
||||||
class ResetUserPassword implements ResetsUserPasswords
|
|
||||||
{
|
|
||||||
use PasswordValidationRules;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate and reset the user's forgotten password.
|
|
||||||
*
|
|
||||||
* @param array<string, string> $input
|
|
||||||
*/
|
|
||||||
public function reset(User $user, array $input): void
|
|
||||||
{
|
|
||||||
Validator::make($input, [
|
|
||||||
'password' => $this->passwordRules(),
|
|
||||||
])->validate();
|
|
||||||
|
|
||||||
$user->forceFill([
|
|
||||||
'password' => Hash::make($input['password']),
|
|
||||||
])->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Fortify;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
|
|
||||||
|
|
||||||
class UpdateUserPassword implements UpdatesUserPasswords
|
|
||||||
{
|
|
||||||
use PasswordValidationRules;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate and update the user's password.
|
|
||||||
*
|
|
||||||
* @param array<string, string> $input
|
|
||||||
*/
|
|
||||||
public function update(User $user, array $input): void
|
|
||||||
{
|
|
||||||
Validator::make($input, [
|
|
||||||
'current_password' => ['required', 'string', 'current_password:web'],
|
|
||||||
'password' => $this->passwordRules(),
|
|
||||||
], [
|
|
||||||
'current_password.current_password' => __('The provided password does not match your current password.'),
|
|
||||||
])->validateWithBag('updatePassword');
|
|
||||||
|
|
||||||
$user->forceFill([
|
|
||||||
'password' => Hash::make($input['password']),
|
|
||||||
])->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Fortify;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
|
|
||||||
|
|
||||||
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Validate and update the given user's profile information.
|
|
||||||
*
|
|
||||||
* @param array<string, string> $input
|
|
||||||
*/
|
|
||||||
public function update(User $user, array $input): void
|
|
||||||
{
|
|
||||||
Validator::make($input, [
|
|
||||||
'name' => ['required', 'string', 'max:255'],
|
|
||||||
|
|
||||||
'email' => [
|
|
||||||
'required',
|
|
||||||
'string',
|
|
||||||
'email',
|
|
||||||
'max:255',
|
|
||||||
Rule::unique('users')->ignore($user->id),
|
|
||||||
],
|
|
||||||
])->validateWithBag('updateProfileInformation');
|
|
||||||
|
|
||||||
if ($input['email'] !== $user->email &&
|
|
||||||
$user instanceof MustVerifyEmail) {
|
|
||||||
$this->updateVerifiedUser($user, $input);
|
|
||||||
} else {
|
|
||||||
$user->forceFill([
|
|
||||||
'name' => $input['name'],
|
|
||||||
'email' => $input['email'],
|
|
||||||
])->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the given verified user's profile information.
|
|
||||||
*
|
|
||||||
* @param array<string, string> $input
|
|
||||||
*/
|
|
||||||
protected function updateVerifiedUser(User $user, array $input): void
|
|
||||||
{
|
|
||||||
$user->forceFill([
|
|
||||||
'name' => $input['name'],
|
|
||||||
'email' => $input['email'],
|
|
||||||
'email_verified_at' => null,
|
|
||||||
])->save();
|
|
||||||
|
|
||||||
$user->sendEmailVerificationNotification();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\License;
|
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class CheckResaleLicense
|
|
||||||
{
|
|
||||||
public function __invoke()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$settings = InstanceSettings::get();
|
|
||||||
$instance_id = config('app.id');
|
|
||||||
if (!$settings->resale_license) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ray('Checking license key');
|
|
||||||
$data = Http::withHeaders([
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
])->post('https://api.lemonsqueezy.com/v1/licenses/validate', [
|
|
||||||
'license_key' => $settings->resale_license,
|
|
||||||
'instance_name' => $instance_id,
|
|
||||||
])->throw()->json();
|
|
||||||
$product_id = (int)data_get($data, 'meta.product_id');
|
|
||||||
$valid_product_id = (int)config('coolify.lemon_squeezy_product_id');
|
|
||||||
if ($product_id !== $valid_product_id) {
|
|
||||||
throw new \Exception('Invalid product id');
|
|
||||||
}
|
|
||||||
ray('Valid Product Id');
|
|
||||||
|
|
||||||
['valid' => $valid, 'license_key' => $license_key] = $data;
|
|
||||||
|
|
||||||
if ($valid) {
|
|
||||||
if (data_get($license_key, 'status') === 'inactive') {
|
|
||||||
Http::withHeaders([
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
])->post('https://api.lemonsqueezy.com/v1/licenses/activate', [
|
|
||||||
'license_key' => $settings->resale_license,
|
|
||||||
'instance_name' => $instance_id,
|
|
||||||
])->throw()->json();
|
|
||||||
}
|
|
||||||
$settings->update([
|
|
||||||
'is_resale_license_active' => true,
|
|
||||||
]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new \Exception('Invalid license key');
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
ray($th);
|
|
||||||
$settings->update([
|
|
||||||
'resale_license' => null,
|
|
||||||
'is_resale_license_active' => false,
|
|
||||||
]);
|
|
||||||
throw $th;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Proxy;
|
|
||||||
|
|
||||||
use App\Enums\ProxyTypes;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class CheckProxySettingsInSync
|
|
||||||
{
|
|
||||||
public function __invoke(Server $server, bool $reset = false)
|
|
||||||
{
|
|
||||||
$proxy_path = config('coolify.proxy_config_path');
|
|
||||||
$output = instant_remote_process([
|
|
||||||
"cat $proxy_path/docker-compose.yml",
|
|
||||||
], $server, false);
|
|
||||||
if (is_null($output) || $reset) {
|
|
||||||
$final_output = Str::of(getProxyConfiguration($server))->trim()->value;
|
|
||||||
} else {
|
|
||||||
$final_output = Str::of($output)->trim()->value;
|
|
||||||
}
|
|
||||||
$docker_compose_yml_base64 = base64_encode($final_output);
|
|
||||||
$server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
|
||||||
$server->save();
|
|
||||||
if (is_null($output) || $reset) {
|
|
||||||
instant_remote_process([
|
|
||||||
"mkdir -p $proxy_path",
|
|
||||||
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
|
||||||
], $server);
|
|
||||||
}
|
|
||||||
return $final_output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Proxy;
|
|
||||||
|
|
||||||
use App\Enums\ProxyStatus;
|
|
||||||
use App\Enums\ProxyTypes;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Spatie\Activitylog\Models\Activity;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class StartProxy
|
|
||||||
{
|
|
||||||
public function __invoke(Server $server): Activity
|
|
||||||
{
|
|
||||||
// TODO: check for other proxies
|
|
||||||
if (is_null(data_get($server, 'proxy.type'))) {
|
|
||||||
$server->proxy->type = ProxyTypes::TRAEFIK_V2->value;
|
|
||||||
$server->proxy->status = ProxyStatus::EXITED->value;
|
|
||||||
$server->save();
|
|
||||||
}
|
|
||||||
$proxy_path = config('coolify.proxy_config_path');
|
|
||||||
|
|
||||||
$networks = collect($server->standaloneDockers)->map(function ($docker) {
|
|
||||||
return $docker['network'];
|
|
||||||
})->unique();
|
|
||||||
if ($networks->count() === 0) {
|
|
||||||
$networks = collect(['coolify']);
|
|
||||||
}
|
|
||||||
$create_networks_command = $networks->map(function ($network) {
|
|
||||||
return "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null 2>&1 || docker network create --attachable $network > /dev/null 2>&1";
|
|
||||||
});
|
|
||||||
|
|
||||||
$configuration = instant_remote_process([
|
|
||||||
"cat $proxy_path/docker-compose.yml",
|
|
||||||
], $server, false);
|
|
||||||
if (is_null($configuration)) {
|
|
||||||
$configuration = Str::of(getProxyConfiguration($server))->trim()->value;
|
|
||||||
} else {
|
|
||||||
$configuration = Str::of($configuration)->trim()->value;
|
|
||||||
}
|
|
||||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
|
||||||
$server->proxy->last_applied_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
|
||||||
$server->save();
|
|
||||||
$activity = remote_process([
|
|
||||||
"echo 'Creating required Docker networks...'",
|
|
||||||
...$create_networks_command,
|
|
||||||
"mkdir -p $proxy_path",
|
|
||||||
"cd $proxy_path",
|
|
||||||
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
|
||||||
"echo 'Creating Docker Compose file...'",
|
|
||||||
"echo 'Pulling docker image...'",
|
|
||||||
'docker compose pull -q',
|
|
||||||
"echo 'Stopping old proxy...'",
|
|
||||||
'docker compose down -v --remove-orphans',
|
|
||||||
"echo 'Starting new proxy...'",
|
|
||||||
'docker compose up -d --remove-orphans',
|
|
||||||
"echo 'Proxy installed successfully...'"
|
|
||||||
], $server);
|
|
||||||
|
|
||||||
return $activity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Server;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\StandaloneDocker;
|
|
||||||
use App\Models\Team;
|
|
||||||
|
|
||||||
class InstallDocker
|
|
||||||
{
|
|
||||||
public function __invoke(Server $server, Team $team)
|
|
||||||
{
|
|
||||||
$dockerVersion = '23.0';
|
|
||||||
$config = base64_encode('{ "live-restore": true }');
|
|
||||||
$activity = remote_process([
|
|
||||||
"echo ####### Installing Prerequisites...",
|
|
||||||
"command -v jq >/dev/null || apt-get update",
|
|
||||||
"command -v jq >/dev/null || apt install -y jq",
|
|
||||||
"echo ####### Installing/updating Docker Engine...",
|
|
||||||
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
|
|
||||||
"echo ####### Configuring Docker Engine (merging existing configuration with the required)...",
|
|
||||||
"test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json \"/etc/docker/daemon.json.original-`date +\"%Y%m%d-%H%M%S\"`\" || echo '{$config}' | base64 -d > /etc/docker/daemon.json",
|
|
||||||
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
|
|
||||||
"cat <<< $(jq . /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json.coolify",
|
|
||||||
"cat <<< $(jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify) > /etc/docker/daemon.json",
|
|
||||||
"echo ####### Restarting Docker Engine...",
|
|
||||||
"systemctl restart docker",
|
|
||||||
"echo ####### Creating default network...",
|
|
||||||
"docker network create --attachable coolify",
|
|
||||||
"echo ####### Done!"
|
|
||||||
], $server);
|
|
||||||
StandaloneDocker::create([
|
|
||||||
'name' => 'coolify',
|
|
||||||
'network' => 'coolify',
|
|
||||||
'server_id' => $server->id,
|
|
||||||
'team_id' => $team->id
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $activity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Server;
|
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
|
||||||
use App\Models\Server;
|
|
||||||
|
|
||||||
class UpdateCoolify
|
|
||||||
{
|
|
||||||
public Server $server;
|
|
||||||
public string $latest_version;
|
|
||||||
public string $current_version;
|
|
||||||
|
|
||||||
public function __invoke(bool $force)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$settings = InstanceSettings::get();
|
|
||||||
ray('Running InstanceAutoUpdateJob');
|
|
||||||
$localhost_name = 'localhost';
|
|
||||||
if (isDev()) {
|
|
||||||
$localhost_name = 'testing-local-docker-container';
|
|
||||||
}
|
|
||||||
$this->server = Server::where('name', $localhost_name)->firstOrFail();
|
|
||||||
$this->latest_version = get_latest_version_of_coolify();
|
|
||||||
$this->current_version = config('version');
|
|
||||||
ray('latest version:' . $this->latest_version . " current version: " . $this->current_version . ' force: ' . $force);
|
|
||||||
if ($settings->next_channel) {
|
|
||||||
ray('next channel enabled');
|
|
||||||
$this->latest_version = 'next';
|
|
||||||
}
|
|
||||||
if ($force) {
|
|
||||||
$this->update();
|
|
||||||
} else {
|
|
||||||
if (!$settings->is_auto_update_enabled) {
|
|
||||||
throw new \Exception('Auto update is disabled');
|
|
||||||
}
|
|
||||||
if ($this->latest_version === $this->current_version) {
|
|
||||||
throw new \Exception('Already on latest version');
|
|
||||||
}
|
|
||||||
if (version_compare($this->latest_version, $this->current_version, '<')) {
|
|
||||||
throw new \Exception('Latest version is lower than current version?!');
|
|
||||||
}
|
|
||||||
$this->update();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
ray('InstanceAutoUpdateJob failed');
|
|
||||||
ray($e->getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private function update()
|
|
||||||
{
|
|
||||||
if (isDev()) {
|
|
||||||
ray("Running update on local docker container. Updating to $this->latest_version");
|
|
||||||
remote_process([
|
|
||||||
"sleep 10"
|
|
||||||
], $this->server);
|
|
||||||
ray('Update done');
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
ray('Running update on production server');
|
|
||||||
remote_process([
|
|
||||||
"curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh",
|
|
||||||
"bash /data/coolify/source/upgrade.sh $this->latest_version"
|
|
||||||
], $this->server);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use App\Enums\ApplicationDeploymentStatus;
|
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
class Init extends Command
|
|
||||||
{
|
|
||||||
protected $signature = 'app:init';
|
|
||||||
protected $description = 'Cleanup instance related stuffs';
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$this->cleanup_in_progress_application_deployments();
|
|
||||||
}
|
|
||||||
private function cleanup_in_progress_application_deployments()
|
|
||||||
{
|
|
||||||
// Cleanup any failed deployments
|
|
||||||
|
|
||||||
try {
|
|
||||||
$halted_deployments = ApplicationDeploymentQueue::where('status', '==', 'in_progress')->get();
|
|
||||||
foreach ($halted_deployments as $deployment) {
|
|
||||||
$deployment->status = ApplicationDeploymentStatus::FAILED->value;
|
|
||||||
$deployment->save();
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
echo "Error: {$e->getMessage()}\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use function Termwind\ask;
|
|
||||||
use function Termwind\render;
|
|
||||||
use function Termwind\style;
|
|
||||||
|
|
||||||
class NotifyDemo extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'app:demo-notify {channel?}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Send a demo notification, to a given channel. Run to see options.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$channel = $this->argument('channel');
|
|
||||||
|
|
||||||
if (blank($channel)) {
|
|
||||||
$this->showHelp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ray($channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function showHelp()
|
|
||||||
{
|
|
||||||
style('coolify')->color('#9333EA');
|
|
||||||
style('title-box')->apply('mt-1 px-2 py-1 bg-coolify');
|
|
||||||
|
|
||||||
render(<<<'HTML'
|
|
||||||
<div>
|
|
||||||
<div class="title-box">
|
|
||||||
Coolify
|
|
||||||
</div>
|
|
||||||
<p class="ml-1 mt-1 ">
|
|
||||||
Demo Notify <strong class="text-coolify">=></strong> Send a demo notification to a given channel.
|
|
||||||
</p>
|
|
||||||
<p class="ml-1 mt-1 bg-coolify px-1">
|
|
||||||
php artisan app:demo-notify {channel}
|
|
||||||
</p>
|
|
||||||
<div class="my-1">
|
|
||||||
<div class="text-yellow-500"> Channels: </div>
|
|
||||||
<ul class="text-coolify">
|
|
||||||
<li>email</li>
|
|
||||||
<li>slack</li>
|
|
||||||
<li>discord</li>
|
|
||||||
<li>telegram</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
HTML);
|
|
||||||
|
|
||||||
ask(<<<'HTML'
|
|
||||||
<div class="mr-1">
|
|
||||||
In which manner you wish a <strong class="text-coolify">coolified</strong> notification?
|
|
||||||
</div>
|
|
||||||
HTML, ['email', 'slack', 'discord', 'telegram']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Http\Client\PendingRequest;
|
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
use Illuminate\Http\Client\Pool;
|
|
||||||
|
|
||||||
class SyncBunny extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'sync:bunny';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Sync files to BunnyCDN';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$bunny_cdn = "https://cdn.coollabs.io";
|
|
||||||
$bunny_cdn_path = "coolify";
|
|
||||||
$bunny_cdn_storage_name = "coolcdn";
|
|
||||||
|
|
||||||
$parent_dir = realpath(dirname(__FILE__) . '/../../..');
|
|
||||||
|
|
||||||
$compose_file = "docker-compose.yml";
|
|
||||||
$compose_file_prod = "docker-compose.prod.yml";
|
|
||||||
$install_script = "install.sh";
|
|
||||||
$upgrade_script = "upgrade.sh";
|
|
||||||
$production_env = ".env.production";
|
|
||||||
|
|
||||||
$versions = "versions.json";
|
|
||||||
|
|
||||||
PendingRequest::macro('storage', function ($file) {
|
|
||||||
$headers = [
|
|
||||||
'AccessKey' => env('BUNNY_STORAGE_API_KEY'),
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
'Content-Type' => 'application/octet-stream'
|
|
||||||
];
|
|
||||||
$fileStream = fopen($file, "r");
|
|
||||||
$file = fread($fileStream, filesize($file));
|
|
||||||
return PendingRequest::baseUrl('https://storage.bunnycdn.com')->withHeaders($headers)->withBody($file)->throw();
|
|
||||||
});
|
|
||||||
PendingRequest::macro('purge', function ($url) {
|
|
||||||
$headers = [
|
|
||||||
'AccessKey' => env('BUNNY_API_KEY'),
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
];
|
|
||||||
ray('Purging: ' . $url);
|
|
||||||
return PendingRequest::withHeaders($headers)->get('https://api.bunny.net/purge', [
|
|
||||||
"url" => $url,
|
|
||||||
"async" => false
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
Http::pool(fn (Pool $pool) => [
|
|
||||||
$pool->storage(file: "$parent_dir/$compose_file")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file"),
|
|
||||||
$pool->storage(file: "$parent_dir/$compose_file_prod")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file_prod"),
|
|
||||||
$pool->storage(file: "$parent_dir/$production_env")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$production_env"),
|
|
||||||
$pool->storage(file: "$parent_dir/scripts/$upgrade_script")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$upgrade_script"),
|
|
||||||
$pool->storage(file: "$parent_dir/scripts/$install_script")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$install_script"),
|
|
||||||
$pool->storage(file: "$parent_dir/$versions")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$versions"),
|
|
||||||
]);
|
|
||||||
ray("{$bunny_cdn}/{$bunny_cdn_path}");
|
|
||||||
Http::pool(fn (Pool $pool) => [
|
|
||||||
$pool->purge("$bunny_cdn/$bunny_cdn_path/$compose_file"),
|
|
||||||
$pool->purge("$bunny_cdn/$bunny_cdn_path/$compose_file_prod"),
|
|
||||||
$pool->purge("$bunny_cdn/$bunny_cdn_path/$production_env"),
|
|
||||||
$pool->purge("$bunny_cdn/$bunny_cdn_path/$upgrade_script"),
|
|
||||||
$pool->purge("$bunny_cdn/$bunny_cdn_path/$install_script"),
|
|
||||||
$pool->purge("$bunny_cdn/$bunny_cdn_path/$versions"),
|
|
||||||
]);
|
|
||||||
echo "All files uploaded & purged...\n";
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
echo $e->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console;
|
|
||||||
|
|
||||||
use App\Jobs\CheckResaleLicenseJob;
|
|
||||||
use App\Jobs\InstanceAutoUpdateJob;
|
|
||||||
use App\Jobs\ProxyCheckJob;
|
|
||||||
use App\Jobs\DockerCleanupJob;
|
|
||||||
use App\Jobs\CheckResaleLicenseKeys;
|
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
|
||||||
|
|
||||||
class Kernel extends ConsoleKernel
|
|
||||||
{
|
|
||||||
protected function schedule(Schedule $schedule): void
|
|
||||||
{
|
|
||||||
if (isDev()) {
|
|
||||||
$schedule->command('horizon:snapshot')->everyMinute();
|
|
||||||
$schedule->job(new ProxyCheckJob)->everyFiveMinutes();
|
|
||||||
// $schedule->job(new CheckResaleLicenseJob)->hourly();
|
|
||||||
// $schedule->job(new DockerCleanupJob)->everyOddHour();
|
|
||||||
// $schedule->job(new InstanceAutoUpdateJob(true))->everyMinute();
|
|
||||||
} else {
|
|
||||||
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
|
||||||
$schedule->job(new CheckResaleLicenseJob)->hourly();
|
|
||||||
$schedule->job(new ProxyCheckJob)->everyFiveMinutes();
|
|
||||||
$schedule->job(new DockerCleanupJob)->everyTenMinutes();
|
|
||||||
$schedule->job(new InstanceAutoUpdateJob)->everyTenMinutes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected function commands(): void
|
|
||||||
{
|
|
||||||
$this->load(__DIR__ . '/Commands');
|
|
||||||
|
|
||||||
require base_path('routes/console.php');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Data;
|
|
||||||
|
|
||||||
use App\Enums\ProcessStatus;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Spatie\LaravelData\Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameters to execute a CoolifyTask, organized in a DTO.
|
|
||||||
*/
|
|
||||||
class CoolifyTaskArgs extends Data
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
public string $server_ip,
|
|
||||||
public string $private_key_location,
|
|
||||||
public string $command,
|
|
||||||
public int $port,
|
|
||||||
public string $user,
|
|
||||||
public string $type,
|
|
||||||
public ?string $type_uuid = null,
|
|
||||||
public ?Model $model = null,
|
|
||||||
public string $status = ProcessStatus::QUEUED->value,
|
|
||||||
public bool $ignore_errors = false,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Data;
|
|
||||||
|
|
||||||
use App\Enums\ProxyStatus;
|
|
||||||
use App\Enums\ProxyTypes;
|
|
||||||
use Spatie\LaravelData\Data;
|
|
||||||
|
|
||||||
class ServerMetadata extends Data
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
public ?ProxyTypes $type,
|
|
||||||
public ?ProxyStatus $status
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
enum ActivityTypes: string
|
|
||||||
{
|
|
||||||
case INLINE = 'inline';
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
enum ApplicationDeploymentStatus: string
|
|
||||||
{
|
|
||||||
case QUEUED = 'queued';
|
|
||||||
case IN_PROGRESS = 'in_progress';
|
|
||||||
case FINISHED = 'finished';
|
|
||||||
case FAILED = 'failed';
|
|
||||||
case CANCELLED_BY_USER = 'cancelled-by-user';
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
enum ProcessStatus: string
|
|
||||||
{
|
|
||||||
case QUEUED = 'queued';
|
|
||||||
case IN_PROGRESS = 'in_progress';
|
|
||||||
case FINISHED = 'finished';
|
|
||||||
case ERROR = 'error';
|
|
||||||
case CANCELLED = 'cancelled';
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
enum ProxyTypes: string
|
|
||||||
{
|
|
||||||
case TRAEFIK_V2 = 'TRAEFIK_V2';
|
|
||||||
case NGINX = 'NGINX';
|
|
||||||
case CADDY = 'CADDY';
|
|
||||||
}
|
|
||||||
enum ProxyStatus: string
|
|
||||||
{
|
|
||||||
case EXITED = 'exited';
|
|
||||||
case RUNNING = 'running';
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Exceptions;
|
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
|
||||||
use Throwable;
|
|
||||||
use Sentry\Laravel\Integration;
|
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
private InstanceSettings $settings;
|
|
||||||
/**
|
|
||||||
* A list of exception types with their corresponding custom log levels.
|
|
||||||
*
|
|
||||||
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
|
|
||||||
*/
|
|
||||||
protected $levels = [
|
|
||||||
//
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of the exception types that are not reported.
|
|
||||||
*
|
|
||||||
* @var array<int, class-string<\Throwable>>
|
|
||||||
*/
|
|
||||||
protected $dontReport = [
|
|
||||||
//
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of the inputs that are never flashed to the session on validation exceptions.
|
|
||||||
*
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $dontFlash = [
|
|
||||||
'current_password',
|
|
||||||
'password',
|
|
||||||
'password_confirmation',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the exception handling callbacks for the application.
|
|
||||||
*/
|
|
||||||
public function register(): void
|
|
||||||
{
|
|
||||||
$this->reportable(function (Throwable $e) {
|
|
||||||
$this->settings = InstanceSettings::get();
|
|
||||||
if ($this->settings->do_not_track || isDev()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Integration::captureUnhandledException($e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Spatie\Activitylog\Models\Activity;
|
|
||||||
|
|
||||||
class ApplicationController extends Controller
|
|
||||||
{
|
|
||||||
use AuthorizesRequests, ValidatesRequests;
|
|
||||||
public function configuration()
|
|
||||||
{
|
|
||||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
|
||||||
if (!$project) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
|
|
||||||
if (!$environment) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
|
|
||||||
if (!$application) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
return view('project.application.configuration', ['application' => $application]);
|
|
||||||
}
|
|
||||||
public function deployments()
|
|
||||||
{
|
|
||||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
|
||||||
if (!$project) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
|
|
||||||
if (!$environment) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
|
|
||||||
if (!$application) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
['deployments' => $deployments, 'count' => $count] = $application->deployments(0, 8);
|
|
||||||
return view('project.application.deployments', ['application' => $application, 'deployments' => $deployments, 'deployments_count' => $count]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deployment()
|
|
||||||
{
|
|
||||||
$deploymentUuid = request()->route('deployment_uuid');
|
|
||||||
|
|
||||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
|
||||||
if (!$project) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
|
|
||||||
if (!$environment) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
|
|
||||||
if (!$application) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
// $activity = Activity::where('properties->type_uuid', '=', $deploymentUuid)->first();
|
|
||||||
// if (!$activity) {
|
|
||||||
// return redirect()->route('project.application.deployments', [
|
|
||||||
// 'project_uuid' => $project->uuid,
|
|
||||||
// 'environment_name' => $environment->name,
|
|
||||||
// 'application_uuid' => $application->uuid,
|
|
||||||
// ]);
|
|
||||||
// }
|
|
||||||
$application_deployment_queue = ApplicationDeploymentQueue::where('deployment_uuid', $deploymentUuid)->first();
|
|
||||||
if (!$application_deployment_queue) {
|
|
||||||
return redirect()->route('project.application.deployments', [
|
|
||||||
'project_uuid' => $project->uuid,
|
|
||||||
'environment_name' => $environment->name,
|
|
||||||
'application_uuid' => $application->uuid,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
return view('project.application.deployment', [
|
|
||||||
'application' => $application,
|
|
||||||
// 'activity' => $activity,
|
|
||||||
'application_deployment_queue' => $application_deployment_queue,
|
|
||||||
'deployment_uuid' => $deploymentUuid,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Livewire\Team\Invitations;
|
|
||||||
use App\Models\InstanceSettings;
|
|
||||||
use App\Models\Project;
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\TeamInvitation;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
|
||||||
use Illuminate\Routing\Controller as BaseController;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class Controller extends BaseController
|
|
||||||
{
|
|
||||||
use AuthorizesRequests, ValidatesRequests;
|
|
||||||
|
|
||||||
public function subscription()
|
|
||||||
{
|
|
||||||
if (!isCloud()) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
return view('subscription', [
|
|
||||||
'settings' => InstanceSettings::get()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function license()
|
|
||||||
{
|
|
||||||
if (!isCloud()) {
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
return view('settings.license', [
|
|
||||||
'settings' => InstanceSettings::get()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function dashboard()
|
|
||||||
{
|
|
||||||
$projects = Project::ownedByCurrentTeam()->get();
|
|
||||||
$servers = Server::ownedByCurrentTeam()->get();
|
|
||||||
|
|
||||||
$resources = 0;
|
|
||||||
foreach ($projects as $project) {
|
|
||||||
$resources += $project->applications->count();
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('dashboard', [
|
|
||||||
'servers' => $servers->count(),
|
|
||||||
'projects' => $projects->count(),
|
|
||||||
'resources' => $resources,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function settings()
|
|
||||||
{
|
|
||||||
if (auth()->user()->isInstanceAdmin()) {
|
|
||||||
$settings = InstanceSettings::get();
|
|
||||||
return view('settings.configuration', [
|
|
||||||
'settings' => $settings
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function emails()
|
|
||||||
{
|
|
||||||
if (auth()->user()->isInstanceAdmin()) {
|
|
||||||
$settings = InstanceSettings::get();
|
|
||||||
return view('settings.emails', [
|
|
||||||
'settings' => $settings
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function team()
|
|
||||||
{
|
|
||||||
$invitations = [];
|
|
||||||
if (auth()->user()->isAdminFromSession()) {
|
|
||||||
$invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
|
|
||||||
}
|
|
||||||
return view('team.show', [
|
|
||||||
'invitations' => $invitations,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function members()
|
|
||||||
{
|
|
||||||
$invitations = [];
|
|
||||||
if (auth()->user()->isAdminFromSession()) {
|
|
||||||
$invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
|
|
||||||
}
|
|
||||||
return view('team.members', [
|
|
||||||
'invitations' => $invitations,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function acceptInvitation()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();
|
|
||||||
$user = User::whereEmail($invitation->email)->firstOrFail();
|
|
||||||
if (is_null(auth()->user())) {
|
|
||||||
return redirect()->route('login');
|
|
||||||
}
|
|
||||||
if (auth()->user()->id !== $user->id) {
|
|
||||||
abort(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
$createdAt = $invitation->created_at;
|
|
||||||
$diff = $createdAt->diffInMinutes(now());
|
|
||||||
if ($diff <= config('constants.invitation.link.expiration')) {
|
|
||||||
$user->teams()->attach($invitation->team->id, ['role' => $invitation->role]);
|
|
||||||
$invitation->delete();
|
|
||||||
return redirect()->route('team.show');
|
|
||||||
} else {
|
|
||||||
$invitation->delete();
|
|
||||||
abort(401);
|
|
||||||
}
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
throw $th;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function revokeInvitation()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail();
|
|
||||||
$user = User::whereEmail($invitation->email)->firstOrFail();
|
|
||||||
if (is_null(auth()->user())) {
|
|
||||||
return redirect()->route('login');
|
|
||||||
}
|
|
||||||
if (auth()->user()->id !== $user->id) {
|
|
||||||
abort(401);
|
|
||||||
}
|
|
||||||
$invitation->delete();
|
|
||||||
return redirect()->route('team.show');
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
throw $th;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Livewire\Server\PrivateKey;
|
|
||||||
use App\Models\Environment;
|
|
||||||
use App\Models\Project;
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\Team;
|
|
||||||
|
|
||||||
class MagicController extends Controller
|
|
||||||
{
|
|
||||||
public function servers()
|
|
||||||
{
|
|
||||||
return response()->json([
|
|
||||||
'servers' => Server::isUsable()->get()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function destinations()
|
|
||||||
{
|
|
||||||
return response()->json([
|
|
||||||
'destinations' => Server::destinationsByServer(request()->query('server_id'))->sortBy('name')
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function projects()
|
|
||||||
{
|
|
||||||
return response()->json([
|
|
||||||
'projects' => Project::ownedByCurrentTeam()->get()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function environments()
|
|
||||||
{
|
|
||||||
return response()->json([
|
|
||||||
'environments' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->first()->environments
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function newProject()
|
|
||||||
{
|
|
||||||
$project = Project::firstOrCreate(
|
|
||||||
['name' => request()->query('name') ?? generate_random_name()],
|
|
||||||
['team_id' => session('currentTeam')->id]
|
|
||||||
);
|
|
||||||
return response()->json([
|
|
||||||
'project_uuid' => $project->uuid
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function newEnvironment()
|
|
||||||
{
|
|
||||||
$environment = Environment::firstOrCreate(
|
|
||||||
['name' => request()->query('name') ?? generate_random_name()],
|
|
||||||
['project_id' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->firstOrFail()->id]
|
|
||||||
);
|
|
||||||
return response()->json([
|
|
||||||
'environment_name' => $environment->name,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function newTeam()
|
|
||||||
{
|
|
||||||
$team = Team::create(
|
|
||||||
[
|
|
||||||
'name' => request()->query('name') ?? generate_random_name(),
|
|
||||||
'personal_team' => false,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
auth()->user()->teams()->attach($team, ['role' => 'admin']);
|
|
||||||
session(['currentTeam' => $team]);
|
|
||||||
return redirect(request()->header('Referer'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Models\Project;
|
|
||||||
|
|
||||||
class ProjectController extends Controller
|
|
||||||
{
|
|
||||||
public function all()
|
|
||||||
{
|
|
||||||
$teamId = session('currentTeam')->id;
|
|
||||||
|
|
||||||
$projects = Project::where('team_id', $teamId)->get();
|
|
||||||
return view('projects', ['projects' => $projects]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function edit()
|
|
||||||
{
|
|
||||||
$projectUuid = request()->route('project_uuid');
|
|
||||||
$teamId = session('currentTeam')->id;
|
|
||||||
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
|
|
||||||
if (!$project) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
return view('project.edit', ['project' => $project]);
|
|
||||||
}
|
|
||||||
public function show()
|
|
||||||
{
|
|
||||||
$projectUuid = request()->route('project_uuid');
|
|
||||||
$teamId = session('currentTeam')->id;
|
|
||||||
|
|
||||||
$project = Project::where('team_id', $teamId)->where('uuid', $projectUuid)->first();
|
|
||||||
if (!$project) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$project->load(['environments']);
|
|
||||||
if (count($project->environments) == 1) {
|
|
||||||
return redirect()->route('project.resources', ['project_uuid' => $project->uuid, 'environment_name' => $project->environments->first()->name]);
|
|
||||||
}
|
|
||||||
return view('project.show', ['project' => $project]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function new()
|
|
||||||
{
|
|
||||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
|
||||||
if (!$project) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first();
|
|
||||||
if (!$environment) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
|
|
||||||
$type = request()->query('type');
|
|
||||||
|
|
||||||
return view('project.new', [
|
|
||||||
'type' => $type
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function resources()
|
|
||||||
{
|
|
||||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
|
||||||
if (!$project) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first();
|
|
||||||
if (!$environment) {
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
}
|
|
||||||
return view('project.resources', [
|
|
||||||
'project' => $project,
|
|
||||||
'environment' => $environment
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
|
||||||
|
|
||||||
class Kernel extends HttpKernel
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The application's global HTTP middleware stack.
|
|
||||||
*
|
|
||||||
* These middleware are run during every request to your application.
|
|
||||||
*
|
|
||||||
* @var array<int, class-string|string>
|
|
||||||
*/
|
|
||||||
protected $middleware = [
|
|
||||||
// \App\Http\Middleware\TrustHosts::class,
|
|
||||||
\App\Http\Middleware\TrustProxies::class,
|
|
||||||
\Illuminate\Http\Middleware\HandleCors::class,
|
|
||||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
|
||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
|
||||||
\App\Http\Middleware\TrimStrings::class,
|
|
||||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The application's route middleware groups.
|
|
||||||
*
|
|
||||||
* @var array<string, array<int, class-string|string>>
|
|
||||||
*/
|
|
||||||
protected $middlewareGroups = [
|
|
||||||
'web' => [
|
|
||||||
\App\Http\Middleware\EncryptCookies::class,
|
|
||||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
|
||||||
\Illuminate\Session\Middleware\StartSession::class,
|
|
||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
|
||||||
\App\Http\Middleware\SubscriptionValid::class,
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
'api' => [
|
|
||||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
|
||||||
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
|
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The application's middleware aliases.
|
|
||||||
*
|
|
||||||
* Aliases may be used to conveniently assign middleware to routes and groups.
|
|
||||||
*
|
|
||||||
* @var array<string, class-string|string>
|
|
||||||
*/
|
|
||||||
protected $middlewareAliases = [
|
|
||||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
|
||||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
|
||||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
|
||||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
|
||||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
|
||||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
|
||||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
|
||||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire;
|
|
||||||
|
|
||||||
use App\Enums\ProcessStatus;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Spatie\Activitylog\Models\Activity;
|
|
||||||
|
|
||||||
class ActivityMonitor extends Component
|
|
||||||
{
|
|
||||||
public bool $header = false;
|
|
||||||
public $activityId;
|
|
||||||
public $isPollingActive = false;
|
|
||||||
|
|
||||||
protected $activity;
|
|
||||||
protected $listeners = ['newMonitorActivity'];
|
|
||||||
|
|
||||||
public function hydrateActivity()
|
|
||||||
{
|
|
||||||
$this->activity = Activity::query()
|
|
||||||
->find($this->activityId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function newMonitorActivity($activityId)
|
|
||||||
{
|
|
||||||
$this->activityId = $activityId;
|
|
||||||
|
|
||||||
$this->hydrateActivity();
|
|
||||||
|
|
||||||
$this->isPollingActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function polling()
|
|
||||||
{
|
|
||||||
$this->hydrateActivity();
|
|
||||||
$this->setStatus(ProcessStatus::IN_PROGRESS);
|
|
||||||
$exit_code = data_get($this->activity, 'properties.exitCode');
|
|
||||||
if ($exit_code !== null) {
|
|
||||||
if ($exit_code === 0) {
|
|
||||||
$this->setStatus(ProcessStatus::FINISHED);
|
|
||||||
} else {
|
|
||||||
$this->setStatus(ProcessStatus::ERROR);
|
|
||||||
}
|
|
||||||
$this->isPollingActive = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected function setStatus($status)
|
|
||||||
{
|
|
||||||
$this->activity->properties = $this->activity->properties->merge([
|
|
||||||
'status' => $status,
|
|
||||||
]);
|
|
||||||
$this->activity->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Application;
|
|
||||||
|
|
||||||
use App\Jobs\ApplicationContainerStatusJob;
|
|
||||||
use App\Models\Application;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class Heading extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
public array $parameters;
|
|
||||||
|
|
||||||
protected string $deploymentUuid;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function check_status()
|
|
||||||
{
|
|
||||||
dispatch_sync(new ApplicationContainerStatusJob(
|
|
||||||
application: $this->application,
|
|
||||||
container_name: generate_container_name($this->application->uuid),
|
|
||||||
));
|
|
||||||
$this->application->refresh();
|
|
||||||
}
|
|
||||||
public function deploy(bool $force_rebuild = false)
|
|
||||||
{
|
|
||||||
$this->setDeploymentUuid();
|
|
||||||
queue_application_deployment(
|
|
||||||
application_id: $this->application->id,
|
|
||||||
deployment_uuid: $this->deploymentUuid,
|
|
||||||
force_rebuild: $force_rebuild,
|
|
||||||
);
|
|
||||||
return redirect()->route('project.application.deployment', [
|
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
|
||||||
'application_uuid' => $this->parameters['application_uuid'],
|
|
||||||
'deployment_uuid' => $this->deploymentUuid,
|
|
||||||
'environment_name' => $this->parameters['environment_name'],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function force_deploy_without_cache()
|
|
||||||
{
|
|
||||||
$this->deploy(force_rebuild: true);
|
|
||||||
}
|
|
||||||
public function stop()
|
|
||||||
{
|
|
||||||
remote_process(
|
|
||||||
["docker rm -f {$this->application->uuid}"],
|
|
||||||
$this->application->destination->server
|
|
||||||
);
|
|
||||||
$this->application->status = 'stopped';
|
|
||||||
$this->application->save();
|
|
||||||
}
|
|
||||||
protected function setDeploymentUuid()
|
|
||||||
{
|
|
||||||
$this->deploymentUuid = new Cuid2(7);
|
|
||||||
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire;
|
|
||||||
|
|
||||||
use App\Actions\License\CheckResaleLicense;
|
|
||||||
use App\Models\InstanceSettings;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class CheckLicense extends Component
|
|
||||||
{
|
|
||||||
public InstanceSettings|null $settings = null;
|
|
||||||
public string|null $instance_id = null;
|
|
||||||
protected $rules = [
|
|
||||||
'settings.resale_license' => 'nullable',
|
|
||||||
'settings.is_resale_license_active' => 'nullable',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'settings.resale_license' => 'License',
|
|
||||||
'instance_id' => 'Instance Id (Do not change this)',
|
|
||||||
'settings.is_resale_license_active' => 'Is License Active',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->instance_id = config('app.id');
|
|
||||||
$this->settings = InstanceSettings::get();
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
$this->settings->save();
|
|
||||||
if ($this->settings->resale_license) {
|
|
||||||
try {
|
|
||||||
resolve(CheckResaleLicense::class)();
|
|
||||||
$this->emit('reloadWindow');
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
session()->flash('error', 'Something went wrong. Please contact support. <br>Error: ' . $th->getMessage());
|
|
||||||
ray($th->getMessage());
|
|
||||||
return redirect()->to('/settings/license');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Destination;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Form extends Component
|
|
||||||
{
|
|
||||||
public mixed $destination;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'destination.name' => 'required',
|
|
||||||
'destination.network' => 'required',
|
|
||||||
'destination.server.ip' => 'required',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'destination.name' => 'name',
|
|
||||||
'destination.network' => 'network',
|
|
||||||
'destination.server.ip' => 'IP Address',
|
|
||||||
];
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
$this->destination->save();
|
|
||||||
}
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if ($this->destination->getMorphClass() === 'App\Models\StandaloneDocker') {
|
|
||||||
if ($this->destination->attachedTo()) {
|
|
||||||
return $this->emit('error', 'You must delete all resources before deleting this destination.');
|
|
||||||
}
|
|
||||||
instant_remote_process(["docker network disconnect {$this->destination->network} coolify-proxy"], $this->destination->server, throwError: false);
|
|
||||||
instant_remote_process(['docker network rm -f ' . $this->destination->network], $this->destination->server);
|
|
||||||
}
|
|
||||||
$this->destination->delete();
|
|
||||||
return redirect()->route('dashboard');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Destination\New;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\StandaloneDocker as ModelsStandaloneDocker;
|
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class StandaloneDocker extends Component
|
|
||||||
{
|
|
||||||
public string $name;
|
|
||||||
public string $network;
|
|
||||||
|
|
||||||
public Collection $servers;
|
|
||||||
public Server $server;
|
|
||||||
public int|null $server_id = null;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'name' => 'required|string',
|
|
||||||
'network' => 'required|string',
|
|
||||||
'server_id' => 'required|integer'
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'name' => 'name',
|
|
||||||
'network' => 'network',
|
|
||||||
'server_id' => 'server'
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
if (request()->query('server_id')) {
|
|
||||||
$this->server_id = request()->query('server_id');
|
|
||||||
} else {
|
|
||||||
if ($this->servers->count() > 0) {
|
|
||||||
$this->server_id = $this->servers->first()->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (request()->query('network_name')) {
|
|
||||||
$this->network = request()->query('network_name');
|
|
||||||
} else {
|
|
||||||
$this->network = new Cuid2(7);
|
|
||||||
}
|
|
||||||
$this->name = generate_random_name();
|
|
||||||
}
|
|
||||||
private function createNetworkAndAttachToProxy()
|
|
||||||
{
|
|
||||||
instant_remote_process(['docker network create --attachable ' . $this->network], $this->server, throwError: false);
|
|
||||||
instant_remote_process(["docker network connect $this->network coolify-proxy"], $this->server, throwError: false);
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->validate();
|
|
||||||
try {
|
|
||||||
$this->server = Server::find($this->server_id);
|
|
||||||
$found = $this->server->standaloneDockers()->where('network', $this->network)->first();
|
|
||||||
if ($found) {
|
|
||||||
$this->createNetworkAndAttachToProxy();
|
|
||||||
$this->addError('network', 'Network already added to this server.');
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
$docker = ModelsStandaloneDocker::create([
|
|
||||||
'name' => $this->name,
|
|
||||||
'network' => $this->network,
|
|
||||||
'server_id' => $this->server_id,
|
|
||||||
'team_id' => session('currentTeam')->id
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
$this->createNetworkAndAttachToProxy();
|
|
||||||
return redirect()->route('destination.show', $docker->uuid);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Destination;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Show extends Component
|
|
||||||
{
|
|
||||||
public Server $server;
|
|
||||||
public Collection|array $networks = [];
|
|
||||||
public function scan()
|
|
||||||
{
|
|
||||||
$alreadyAddedNetworks = $this->server->standaloneDockers;
|
|
||||||
$networks = instant_remote_process(['docker network ls --format "{{json .}}"'], $this->server, false);
|
|
||||||
$this->networks = format_docker_command_output_to_json($networks)->filter(function ($network) {
|
|
||||||
return $network['Name'] !== 'bridge' && $network['Name'] !== 'host' && $network['Name'] !== 'none';
|
|
||||||
})->filter(function ($network) use ($alreadyAddedNetworks) {
|
|
||||||
return !$alreadyAddedNetworks->contains('network', $network['Name']);
|
|
||||||
});
|
|
||||||
if ($this->networks->count() === 0) {
|
|
||||||
$this->emit('success', 'No new networks found.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class License extends Component
|
|
||||||
{
|
|
||||||
public string $license;
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
ray('checking license');
|
|
||||||
$this->validate([
|
|
||||||
'license' => 'required'
|
|
||||||
]);
|
|
||||||
// Pretend we're checking the license
|
|
||||||
// if ($this->license === '123') {
|
|
||||||
// ray('license is valid');
|
|
||||||
// Cache::put('license_key', '123');
|
|
||||||
// return redirect()->to('/');
|
|
||||||
// } else {
|
|
||||||
// ray('license is invalid');
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Notifications;
|
|
||||||
|
|
||||||
use App\Models\Team;
|
|
||||||
use App\Notifications\Notifications\TestNotification;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class DiscordSettings extends Component
|
|
||||||
{
|
|
||||||
public Team $model;
|
|
||||||
protected $rules = [
|
|
||||||
'model.discord.enabled' => 'nullable|boolean',
|
|
||||||
'model.discord.webhook_url' => 'required|url',
|
|
||||||
'model.discord_notifications.test' => 'nullable|boolean',
|
|
||||||
'model.discord_notifications.deployments' => 'nullable|boolean',
|
|
||||||
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'model.discord.webhook_url' => 'Discord Webhook',
|
|
||||||
];
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->submit();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->model->discord->enabled = false;
|
|
||||||
$this->validate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function saveModel()
|
|
||||||
{
|
|
||||||
$this->model->save();
|
|
||||||
if (is_a($this->model, Team::class)) {
|
|
||||||
session(['currentTeam' => $this->model]);
|
|
||||||
}
|
|
||||||
$this->emit('success', 'Settings saved.');
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->resetErrorBag();
|
|
||||||
$this->validate();
|
|
||||||
$this->saveModel();
|
|
||||||
}
|
|
||||||
public function sendTestNotification()
|
|
||||||
{
|
|
||||||
$this->model->notify(new TestNotification('discord'));
|
|
||||||
$this->emit('success', 'Test notification sent.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Notifications;
|
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
|
||||||
use App\Models\Team;
|
|
||||||
use App\Notifications\Notifications\TestNotification;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class EmailSettings extends Component
|
|
||||||
{
|
|
||||||
public Team $model;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'model.smtp.enabled' => 'nullable|boolean',
|
|
||||||
'model.smtp.from_address' => 'required|email',
|
|
||||||
'model.smtp.from_name' => 'required',
|
|
||||||
'model.smtp.recipients' => 'nullable',
|
|
||||||
'model.smtp.host' => 'required',
|
|
||||||
'model.smtp.port' => 'required',
|
|
||||||
'model.smtp.encryption' => 'nullable',
|
|
||||||
'model.smtp.username' => 'nullable',
|
|
||||||
'model.smtp.password' => 'nullable',
|
|
||||||
'model.smtp.timeout' => 'nullable',
|
|
||||||
'model.smtp.test_recipients' => 'nullable',
|
|
||||||
'model.smtp_notifications.test' => 'nullable|boolean',
|
|
||||||
'model.smtp_notifications.deployments' => 'nullable|boolean',
|
|
||||||
'model.discord_notifications.test' => 'nullable|boolean',
|
|
||||||
'model.discord_notifications.deployments' => 'nullable|boolean',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'model.smtp.from_address' => 'From Address',
|
|
||||||
'model.smtp.from_name' => 'From Name',
|
|
||||||
'model.smtp.recipients' => 'Recipients',
|
|
||||||
'model.smtp.host' => 'Host',
|
|
||||||
'model.smtp.port' => 'Port',
|
|
||||||
'model.smtp.encryption' => 'Encryption',
|
|
||||||
'model.smtp.username' => 'Username',
|
|
||||||
'model.smtp.password' => 'Password',
|
|
||||||
'model.smtp.test_recipients' => 'Test Recipients',
|
|
||||||
];
|
|
||||||
private function decrypt()
|
|
||||||
{
|
|
||||||
if (data_get($this->model, 'smtp.password')) {
|
|
||||||
try {
|
|
||||||
$this->model->smtp->password = decrypt($this->model->smtp->password);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->decrypt();
|
|
||||||
}
|
|
||||||
public function copyFromInstanceSettings()
|
|
||||||
{
|
|
||||||
$settings = InstanceSettings::get();
|
|
||||||
if ($settings->smtp->enabled) {
|
|
||||||
$this->model->smtp->enabled = true;
|
|
||||||
$this->model->smtp->from_address = $settings->smtp->from_address;
|
|
||||||
$this->model->smtp->from_name = $settings->smtp->from_name;
|
|
||||||
$this->model->smtp->recipients = $settings->smtp->recipients;
|
|
||||||
$this->model->smtp->host = $settings->smtp->host;
|
|
||||||
$this->model->smtp->port = $settings->smtp->port;
|
|
||||||
$this->model->smtp->encryption = $settings->smtp->encryption;
|
|
||||||
$this->model->smtp->username = $settings->smtp->username;
|
|
||||||
$this->model->smtp->password = $settings->smtp->password;
|
|
||||||
$this->model->smtp->timeout = $settings->smtp->timeout;
|
|
||||||
$this->model->smtp->test_recipients = $settings->smtp->test_recipients;
|
|
||||||
$this->saveModel();
|
|
||||||
} else {
|
|
||||||
$this->emit('error', 'Instance SMTP settings are not enabled.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->resetErrorBag();
|
|
||||||
$this->validate();
|
|
||||||
|
|
||||||
if ($this->model->smtp->password) {
|
|
||||||
$this->model->smtp->password = encrypt($this->model->smtp->password);
|
|
||||||
} else {
|
|
||||||
$this->model->smtp->password = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->model->smtp->recipients = str_replace(' ', '', $this->model->smtp->recipients);
|
|
||||||
$this->model->smtp->test_recipients = str_replace(' ', '', $this->model->smtp->test_recipients);
|
|
||||||
$this->saveModel();
|
|
||||||
}
|
|
||||||
public function saveModel()
|
|
||||||
{
|
|
||||||
$this->model->save();
|
|
||||||
$this->decrypt();
|
|
||||||
if (is_a($this->model, Team::class)) {
|
|
||||||
session(['currentTeam' => $this->model]);
|
|
||||||
}
|
|
||||||
$this->emit('success', 'Settings saved.');
|
|
||||||
}
|
|
||||||
public function sendTestNotification()
|
|
||||||
{
|
|
||||||
$this->model->notify(new TestNotification('smtp'));
|
|
||||||
$this->emit('success', 'Test notification sent.');
|
|
||||||
}
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->submit();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->model->smtp->enabled = false;
|
|
||||||
$this->validate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\PrivateKey;
|
|
||||||
|
|
||||||
use App\Models\PrivateKey;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Change extends Component
|
|
||||||
{
|
|
||||||
public PrivateKey $private_key;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'private_key.name' => 'required|string',
|
|
||||||
'private_key.description' => 'nullable|string',
|
|
||||||
'private_key.private_key' => 'required|string',
|
|
||||||
'private_key.is_git_related' => 'nullable|boolean'
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'private_key.name' => 'name',
|
|
||||||
'private_key.description' => 'description',
|
|
||||||
'private_key.private_key' => 'private key'
|
|
||||||
];
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if ($this->private_key->isEmpty()) {
|
|
||||||
$this->private_key->delete();
|
|
||||||
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
|
|
||||||
return redirect()->route('private-key.all');
|
|
||||||
}
|
|
||||||
$this->emit('error', 'This private key is in use and cannot be deleted. Please delete all servers, applications, and GitHub/GitLab apps that use this private key before deleting it.');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function changePrivateKey()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->private_key->private_key = trim($this->private_key->private_key);
|
|
||||||
if (!str_ends_with($this->private_key->private_key, "\n")) {
|
|
||||||
$this->private_key->private_key .= "\n";
|
|
||||||
}
|
|
||||||
$this->private_key->save();
|
|
||||||
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\PrivateKey;
|
|
||||||
|
|
||||||
use App\Models\PrivateKey;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Create extends Component
|
|
||||||
{
|
|
||||||
protected string|null $from = null;
|
|
||||||
public string $name;
|
|
||||||
public string|null $description = null;
|
|
||||||
public string $value;
|
|
||||||
protected $rules = [
|
|
||||||
'name' => 'required|string',
|
|
||||||
'value' => 'required|string',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'name' => 'name',
|
|
||||||
'value' => 'private Key',
|
|
||||||
];
|
|
||||||
public function createPrivateKey()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
try {
|
|
||||||
$this->value = trim($this->value);
|
|
||||||
if (!str_ends_with($this->value, "\n")) {
|
|
||||||
$this->value .= "\n";
|
|
||||||
}
|
|
||||||
$private_key = PrivateKey::create([
|
|
||||||
'name' => $this->name,
|
|
||||||
'description' => $this->description,
|
|
||||||
'private_key' => $this->value,
|
|
||||||
'team_id' => session('currentTeam')->id
|
|
||||||
]);
|
|
||||||
if ($this->from === 'server') {
|
|
||||||
return redirect()->route('server.create');
|
|
||||||
}
|
|
||||||
return redirect()->route('private-key.show', ['private_key_uuid' => $private_key->uuid]);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Profile;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Form extends Component
|
|
||||||
{
|
|
||||||
public int $userId;
|
|
||||||
public string $name;
|
|
||||||
public string $email;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'name' => 'required',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'name' => 'name',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->userId = auth()->user()->id;
|
|
||||||
$this->name = auth()->user()->name;
|
|
||||||
$this->email = auth()->user()->email;
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->validate();
|
|
||||||
User::where('id', $this->userId)->update([
|
|
||||||
'name' => $this->name,
|
|
||||||
]);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class Danger extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
public array $parameters;
|
|
||||||
public string|null $modalId = null;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->modalId = new Cuid2(7);
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
$destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
|
|
||||||
|
|
||||||
instant_remote_process(["docker rm -f {$this->application->uuid}"], $destination->server);
|
|
||||||
$this->application->delete();
|
|
||||||
return redirect()->route('project.resources', [
|
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
|
||||||
'environment_name' => $this->parameters['environment_name']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class DeploymentLogs extends Component
|
|
||||||
{
|
|
||||||
public ApplicationDeploymentQueue $application_deployment_queue;
|
|
||||||
public $isKeepAliveOn = true;
|
|
||||||
protected $listeners = ['refreshQueue'];
|
|
||||||
public function refreshQueue()
|
|
||||||
{
|
|
||||||
$this->application_deployment_queue->refresh();
|
|
||||||
}
|
|
||||||
public function polling()
|
|
||||||
{
|
|
||||||
$this->emit('deploymentFinished');
|
|
||||||
$this->application_deployment_queue->refresh();
|
|
||||||
if (data_get($this->application_deployment_queue, 'status') == 'finished' || data_get($this->application_deployment_queue, 'status') == 'failed') {
|
|
||||||
$this->isKeepAliveOn = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Enums\ApplicationDeploymentStatus;
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Illuminate\Support\Facades\Process;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class DeploymentNavbar extends Component
|
|
||||||
{
|
|
||||||
protected $listeners = ['deploymentFinished'];
|
|
||||||
|
|
||||||
public ApplicationDeploymentQueue $application_deployment_queue;
|
|
||||||
public Application $application;
|
|
||||||
public Server $server;
|
|
||||||
public bool $is_debug_enabled = false;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->application = Application::find($this->application_deployment_queue->application_id);
|
|
||||||
$this->server = $this->application->destination->server;
|
|
||||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
|
||||||
}
|
|
||||||
public function deploymentFinished()
|
|
||||||
{
|
|
||||||
$this->application_deployment_queue->refresh();
|
|
||||||
}
|
|
||||||
public function show_debug()
|
|
||||||
{
|
|
||||||
$this->application->settings->is_debug_enabled = !$this->application->settings->is_debug_enabled;
|
|
||||||
$this->application->settings->save();
|
|
||||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
|
||||||
$this->emit('refreshQueue');
|
|
||||||
}
|
|
||||||
public function cancel()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$kill_command = "kill -9 {$this->application_deployment_queue->current_process_id}";
|
|
||||||
if ($this->application_deployment_queue->current_process_id) {
|
|
||||||
$process = Process::run("ps -p {$this->application_deployment_queue->current_process_id} -o command --no-headers");
|
|
||||||
if (Str::of($process->output())->contains([$this->server->ip, 'EOF-COOLIFY-SSH'])) {
|
|
||||||
Process::run($kill_command);
|
|
||||||
}
|
|
||||||
$previous_logs = json_decode($this->application_deployment_queue->logs, associative: true, flags: JSON_THROW_ON_ERROR);
|
|
||||||
$new_log_entry = [
|
|
||||||
'command' => $kill_command,
|
|
||||||
'output' => "Deployment cancelled by user.",
|
|
||||||
'type' => 'stderr',
|
|
||||||
'order' => count($previous_logs) + 1,
|
|
||||||
'timestamp' => Carbon::now('UTC'),
|
|
||||||
'hidden' => false,
|
|
||||||
];
|
|
||||||
$previous_logs[] = $new_log_entry;
|
|
||||||
$this->application_deployment_queue->update([
|
|
||||||
'logs' => json_encode($previous_logs, flags: JSON_THROW_ON_ERROR),
|
|
||||||
'current_process_id' => null,
|
|
||||||
'status' => ApplicationDeploymentStatus::CANCELLED_BY_USER->value,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Deployments extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
public $deployments = [];
|
|
||||||
public int $deployments_count = 0;
|
|
||||||
public string $current_url;
|
|
||||||
public int $skip = 0;
|
|
||||||
public int $default_take = 8;
|
|
||||||
public bool $show_next = false;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->current_url = url()->current();
|
|
||||||
$this->show_more();
|
|
||||||
}
|
|
||||||
private function show_more()
|
|
||||||
{
|
|
||||||
if (count($this->deployments) !== 0) {
|
|
||||||
$this->show_next = true;
|
|
||||||
if (count($this->deployments) < $this->default_take) {
|
|
||||||
$this->show_next = false;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function reload_deployments()
|
|
||||||
{
|
|
||||||
$this->load_deployments();
|
|
||||||
}
|
|
||||||
public function load_deployments(int|null $take = null)
|
|
||||||
{
|
|
||||||
if ($take) {
|
|
||||||
$this->skip = $this->skip + $take;
|
|
||||||
}
|
|
||||||
$take = $this->default_take;
|
|
||||||
|
|
||||||
['deployments' => $deployments, 'count' => $count] = $this->application->deployments($this->skip, $take);
|
|
||||||
$this->deployments = $deployments;
|
|
||||||
$this->deployments_count = $count;
|
|
||||||
$this->show_more();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Destination extends Component
|
|
||||||
{
|
|
||||||
public $destination;
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application\EnvironmentVariable;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Add extends Component
|
|
||||||
{
|
|
||||||
public $parameters;
|
|
||||||
public bool $is_preview = false;
|
|
||||||
public string $key;
|
|
||||||
public string $value;
|
|
||||||
public bool $is_build_time = false;
|
|
||||||
|
|
||||||
protected $listeners = ['clearAddEnv' => 'clear'];
|
|
||||||
protected $rules = [
|
|
||||||
'key' => 'required|string',
|
|
||||||
'value' => 'required|string',
|
|
||||||
'is_build_time' => 'required|boolean',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'key' => 'key',
|
|
||||||
'value' => 'value',
|
|
||||||
'is_build_time' => 'build',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
ray('submitting');
|
|
||||||
$this->validate();
|
|
||||||
$this->emitUp('submit', [
|
|
||||||
'key' => $this->key,
|
|
||||||
'value' => $this->value,
|
|
||||||
'is_build_time' => $this->is_build_time,
|
|
||||||
'is_preview' => $this->is_preview,
|
|
||||||
]);
|
|
||||||
$this->clear();
|
|
||||||
}
|
|
||||||
public function clear()
|
|
||||||
{
|
|
||||||
$this->key = '';
|
|
||||||
$this->value = '';
|
|
||||||
$this->is_build_time = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application\EnvironmentVariable;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\EnvironmentVariable;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class All extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
public string|null $modalId = null;
|
|
||||||
protected $listeners = ['refreshEnvs', 'submit'];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->modalId = new Cuid2(7);
|
|
||||||
}
|
|
||||||
public function refreshEnvs()
|
|
||||||
{
|
|
||||||
$this->application->refresh();
|
|
||||||
}
|
|
||||||
public function submit($data)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$found = $this->application->environment_variables()->where('key', $data['key'])->first();
|
|
||||||
if ($found) {
|
|
||||||
$this->emit('error', 'Environment variable already exists.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EnvironmentVariable::create([
|
|
||||||
'key' => $data['key'],
|
|
||||||
'value' => $data['value'],
|
|
||||||
'is_build_time' => $data['is_build_time'],
|
|
||||||
'is_preview' => $data['is_preview'],
|
|
||||||
'application_id' => $this->application->id,
|
|
||||||
]);
|
|
||||||
$this->application->refresh();
|
|
||||||
|
|
||||||
$this->emit('success', 'Environment variable added successfully.');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application\EnvironmentVariable;
|
|
||||||
|
|
||||||
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class Show extends Component
|
|
||||||
{
|
|
||||||
public $parameters;
|
|
||||||
public ModelsEnvironmentVariable $env;
|
|
||||||
public string|null $modalId = null;
|
|
||||||
protected $rules = [
|
|
||||||
'env.key' => 'required|string',
|
|
||||||
'env.value' => 'required|string',
|
|
||||||
'env.is_build_time' => 'required|boolean',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'key' => 'key',
|
|
||||||
'value' => 'value',
|
|
||||||
'is_build_time' => 'build',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->modalId = new Cuid2(7);
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
$this->env->save();
|
|
||||||
$this->emit('success', 'Environment variable updated successfully.');
|
|
||||||
}
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
$this->env->delete();
|
|
||||||
$this->emit('refreshEnvs');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\InstanceSettings;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Spatie\Url\Url;
|
|
||||||
|
|
||||||
class General extends Component
|
|
||||||
{
|
|
||||||
public string $applicationId;
|
|
||||||
|
|
||||||
public Application $application;
|
|
||||||
public string $name;
|
|
||||||
public string|null $fqdn;
|
|
||||||
public string $git_repository;
|
|
||||||
public string $git_branch;
|
|
||||||
public string|null $git_commit_sha;
|
|
||||||
public string $build_pack;
|
|
||||||
public string|null $wildcard_domain = null;
|
|
||||||
public string|null $server_wildcard_domain = null;
|
|
||||||
public string|null $global_wildcard_domain = null;
|
|
||||||
|
|
||||||
public bool $is_static;
|
|
||||||
public bool $is_git_submodules_enabled;
|
|
||||||
public bool $is_git_lfs_enabled;
|
|
||||||
public bool $is_debug_enabled;
|
|
||||||
public bool $is_preview_deployments_enabled;
|
|
||||||
public bool $is_auto_deploy_enabled;
|
|
||||||
public bool $is_force_https_enabled;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'application.name' => 'required',
|
|
||||||
'application.fqdn' => 'nullable',
|
|
||||||
'application.git_repository' => 'required',
|
|
||||||
'application.git_branch' => 'required',
|
|
||||||
'application.git_commit_sha' => 'nullable',
|
|
||||||
'application.install_command' => 'nullable',
|
|
||||||
'application.build_command' => 'nullable',
|
|
||||||
'application.start_command' => 'nullable',
|
|
||||||
'application.build_pack' => 'required',
|
|
||||||
'application.static_image' => 'required',
|
|
||||||
'application.base_directory' => 'required',
|
|
||||||
'application.publish_directory' => 'nullable',
|
|
||||||
'application.ports_exposes' => 'required',
|
|
||||||
'application.ports_mappings' => 'nullable',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'application.name' => 'name',
|
|
||||||
'application.fqdn' => 'FQDN',
|
|
||||||
'application.git_repository' => 'Git repository',
|
|
||||||
'application.git_branch' => 'Git branch',
|
|
||||||
'application.git_commit_sha' => 'Git commit SHA',
|
|
||||||
'application.install_command' => 'Install command',
|
|
||||||
'application.build_command' => 'Build command',
|
|
||||||
'application.start_command' => 'Start command',
|
|
||||||
'application.build_pack' => 'Build pack',
|
|
||||||
'application.static_image' => 'Static image',
|
|
||||||
'application.base_directory' => 'Base directory',
|
|
||||||
'application.publish_directory' => 'Publish directory',
|
|
||||||
'application.ports_exposes' => 'Ports exposes',
|
|
||||||
'application.ports_mappings' => 'Ports mappings',
|
|
||||||
];
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
// @TODO: find another way - if possible
|
|
||||||
$this->application->settings->is_static = $this->is_static;
|
|
||||||
if ($this->is_static) {
|
|
||||||
$this->application->ports_exposes = 80;
|
|
||||||
} else {
|
|
||||||
$this->application->ports_exposes = 3000;
|
|
||||||
}
|
|
||||||
$this->application->settings->is_git_submodules_enabled = $this->is_git_submodules_enabled;
|
|
||||||
$this->application->settings->is_git_lfs_enabled = $this->is_git_lfs_enabled;
|
|
||||||
$this->application->settings->is_debug_enabled = $this->is_debug_enabled;
|
|
||||||
$this->application->settings->is_preview_deployments_enabled = $this->is_preview_deployments_enabled;
|
|
||||||
$this->application->settings->is_auto_deploy_enabled = $this->is_auto_deploy_enabled;
|
|
||||||
$this->application->settings->is_force_https_enabled = $this->is_force_https_enabled;
|
|
||||||
$this->application->settings->save();
|
|
||||||
$this->application->save();
|
|
||||||
$this->application->refresh();
|
|
||||||
$this->emit('success', 'Application settings updated!');
|
|
||||||
$this->checkWildCardDomain();
|
|
||||||
}
|
|
||||||
protected function checkWildCardDomain()
|
|
||||||
{
|
|
||||||
$coolify_instance_settings = InstanceSettings::get();
|
|
||||||
$this->server_wildcard_domain = data_get($this->application, 'destination.server.settings.wildcard_domain');
|
|
||||||
$this->global_wildcard_domain = data_get($coolify_instance_settings, 'wildcard_domain');
|
|
||||||
$this->wildcard_domain = $this->server_wildcard_domain ?? $this->global_wildcard_domain ?? null;
|
|
||||||
}
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->is_static = $this->application->settings->is_static;
|
|
||||||
$this->is_git_submodules_enabled = $this->application->settings->is_git_submodules_enabled;
|
|
||||||
$this->is_git_lfs_enabled = $this->application->settings->is_git_lfs_enabled;
|
|
||||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
|
||||||
$this->is_preview_deployments_enabled = $this->application->settings->is_preview_deployments_enabled;
|
|
||||||
$this->is_auto_deploy_enabled = $this->application->settings->is_auto_deploy_enabled;
|
|
||||||
$this->is_force_https_enabled = $this->application->settings->is_force_https_enabled;
|
|
||||||
$this->checkWildCardDomain();
|
|
||||||
}
|
|
||||||
public function generateGlobalRandomDomain()
|
|
||||||
{
|
|
||||||
// Set wildcard domain based on Global wildcard domain
|
|
||||||
$url = Url::fromString($this->global_wildcard_domain);
|
|
||||||
$host = $url->getHost();
|
|
||||||
$path = $url->getPath() === '/' ? '' : $url->getPath();
|
|
||||||
$scheme = $url->getScheme();
|
|
||||||
$this->application->fqdn = $scheme . '://' . $this->application->uuid . '.' . $host . $path;
|
|
||||||
$this->application->save();
|
|
||||||
$this->emit('success', 'Application settings updated!');
|
|
||||||
}
|
|
||||||
public function generateServerRandomDomain()
|
|
||||||
{
|
|
||||||
// Set wildcard domain based on Server wildcard domain
|
|
||||||
$url = Url::fromString($this->server_wildcard_domain);
|
|
||||||
$host = $url->getHost();
|
|
||||||
$path = $url->getPath() === '/' ? '' : $url->getPath();
|
|
||||||
$scheme = $url->getScheme();
|
|
||||||
$this->application->fqdn = $scheme . '://' . $this->application->uuid . '.' . $host . $path;
|
|
||||||
$this->application->save();
|
|
||||||
$this->emit('success', 'Application settings updated!');
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->validate();
|
|
||||||
|
|
||||||
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
|
||||||
return Str::of($domain)->trim()->lower();
|
|
||||||
});
|
|
||||||
if ($this->application->base_directory && $this->application->base_directory !== '/') {
|
|
||||||
$this->application->base_directory = rtrim($this->application->base_directory, '/');
|
|
||||||
}
|
|
||||||
if ($this->application->publish_directory && $this->application->publish_directory !== '/') {
|
|
||||||
$this->application->publish_directory = rtrim($this->application->publish_directory, '/');
|
|
||||||
}
|
|
||||||
$this->application->fqdn = $domains->implode(',');
|
|
||||||
$this->application->save();
|
|
||||||
$this->emit('success', 'Application settings updated!');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application\Preview;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Spatie\Url\Url;
|
|
||||||
|
|
||||||
class Form extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
public string $preview_url_template;
|
|
||||||
protected $rules = [
|
|
||||||
'application.preview_url_template' => 'required',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'application.preview_url_template' => 'preview url template',
|
|
||||||
];
|
|
||||||
public function resetToDefault()
|
|
||||||
{
|
|
||||||
$this->application->preview_url_template = '{{pr_id}}.{{domain}}';
|
|
||||||
$this->preview_url_template = $this->application->preview_url_template;
|
|
||||||
$this->application->save();
|
|
||||||
$this->generate_real_url();
|
|
||||||
}
|
|
||||||
public function generate_real_url()
|
|
||||||
{
|
|
||||||
if (data_get($this->application, 'fqdn')) {
|
|
||||||
$url = Url::fromString($this->application->fqdn);
|
|
||||||
$host = $url->getHost();
|
|
||||||
$this->preview_url_template = Str::of($this->application->preview_url_template)->replace('{{domain}}', $host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->generate_real_url();
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
$this->application->preview_url_template = str_replace(' ', '', $this->application->preview_url_template);
|
|
||||||
$this->application->save();
|
|
||||||
$this->emit('success', 'Preview url template updated successfully.');
|
|
||||||
$this->generate_real_url();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Jobs\ApplicationContainerStatusJob;
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\ApplicationPreview;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class Previews extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
public string $deployment_uuid;
|
|
||||||
public array $parameters;
|
|
||||||
public Collection $pull_requests;
|
|
||||||
public int $rate_limit_remaining;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->pull_requests = collect();
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
public function loadStatus($pull_request_id)
|
|
||||||
{
|
|
||||||
dispatch(new ApplicationContainerStatusJob(
|
|
||||||
application: $this->application,
|
|
||||||
container_name: generate_container_name($this->application->uuid, $pull_request_id),
|
|
||||||
pull_request_id: $pull_request_id
|
|
||||||
));
|
|
||||||
}
|
|
||||||
protected function setDeploymentUuid()
|
|
||||||
{
|
|
||||||
$this->deployment_uuid = new Cuid2(7);
|
|
||||||
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
|
|
||||||
}
|
|
||||||
public function load_prs()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = git_api(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/pulls");
|
|
||||||
$this->rate_limit_remaining = $rate_limit_remaining;
|
|
||||||
$this->pull_requests = $data->sortBy('number')->values();
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$this->rate_limit_remaining = 0;
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function deploy(int $pull_request_id, string|null $pull_request_html_url = null)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->setDeploymentUuid();
|
|
||||||
$found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
|
|
||||||
if (!$found && !is_null($pull_request_html_url)) {
|
|
||||||
ApplicationPreview::create([
|
|
||||||
'application_id' => $this->application->id,
|
|
||||||
'pull_request_id' => $pull_request_id,
|
|
||||||
'pull_request_html_url' => $pull_request_html_url
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
queue_application_deployment(
|
|
||||||
application_id: $this->application->id,
|
|
||||||
deployment_uuid: $this->deployment_uuid,
|
|
||||||
force_rebuild: true,
|
|
||||||
pull_request_id: $pull_request_id,
|
|
||||||
);
|
|
||||||
return redirect()->route('project.application.deployment', [
|
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
|
||||||
'application_uuid' => $this->parameters['application_uuid'],
|
|
||||||
'deployment_uuid' => $this->deployment_uuid,
|
|
||||||
'environment_name' => $this->parameters['environment_name'],
|
|
||||||
]);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function stop(int $pull_request_id)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$container_name = generate_container_name($this->application->uuid, $pull_request_id);
|
|
||||||
ray('Stopping container: ' . $container_name);
|
|
||||||
|
|
||||||
instant_remote_process(["docker rm -f $container_name"], $this->application->destination->server, throwError: false);
|
|
||||||
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete();
|
|
||||||
$this->application->refresh();
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function previewRefresh()
|
|
||||||
{
|
|
||||||
$this->application->previews->each(function ($preview) {
|
|
||||||
$preview->refresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class ResourceLimits extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
protected $rules = [
|
|
||||||
'application.limits_memory' => 'required|string',
|
|
||||||
'application.limits_memory_swap' => 'required|string',
|
|
||||||
'application.limits_memory_swappiness' => 'required|integer|min:0|max:100',
|
|
||||||
'application.limits_memory_reservation' => 'required|string',
|
|
||||||
'application.limits_cpus' => 'nullable',
|
|
||||||
'application.limits_cpuset' => 'nullable',
|
|
||||||
'application.limits_cpu_shares' => 'nullable',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'application.limits_memory' => 'memory',
|
|
||||||
'application.limits_memory_swap' => 'swap',
|
|
||||||
'application.limits_memory_swappiness' => 'swappiness',
|
|
||||||
'application.limits_memory_reservation' => 'reservation',
|
|
||||||
'application.limits_cpus' => 'cpus',
|
|
||||||
'application.limits_cpuset' => 'cpuset',
|
|
||||||
'application.limits_cpu_shares' => 'cpu shares',
|
|
||||||
];
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (!$this->application->limits_memory) {
|
|
||||||
$this->application->limits_memory = "0";
|
|
||||||
}
|
|
||||||
if (!$this->application->limits_memory_swap) {
|
|
||||||
$this->application->limits_memory_swap = "0";
|
|
||||||
}
|
|
||||||
if (!$this->application->limits_memory_swappiness) {
|
|
||||||
$this->application->limits_memory_swappiness = "60";
|
|
||||||
}
|
|
||||||
if (!$this->application->limits_memory_reservation) {
|
|
||||||
$this->application->limits_memory_reservation = "0";
|
|
||||||
}
|
|
||||||
if (!$this->application->limits_cpus) {
|
|
||||||
$this->application->limits_cpus = "0";
|
|
||||||
}
|
|
||||||
if (!$this->application->limits_cpuset) {
|
|
||||||
$this->application->limits_cpuset = "0";
|
|
||||||
}
|
|
||||||
if (!$this->application->limits_cpu_shares) {
|
|
||||||
$this->application->limits_cpu_shares = 1024;
|
|
||||||
}
|
|
||||||
$this->validate();
|
|
||||||
$this->application->save();
|
|
||||||
$this->emit('success', 'Resource limits updated successfully.');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class Rollback extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
public $images = [];
|
|
||||||
public string|null $current;
|
|
||||||
public array $parameters;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
public function rollbackImage($commit)
|
|
||||||
{
|
|
||||||
$deployment_uuid = new Cuid2(7);
|
|
||||||
|
|
||||||
queue_application_deployment(
|
|
||||||
application_id: $this->application->id,
|
|
||||||
deployment_uuid: $deployment_uuid,
|
|
||||||
commit: $commit,
|
|
||||||
force_rebuild: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
return redirect()->route('project.application.deployment', [
|
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
|
||||||
'application_uuid' => $this->parameters['application_uuid'],
|
|
||||||
'deployment_uuid' => $deployment_uuid,
|
|
||||||
'environment_name' => $this->parameters['environment_name'],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function loadImages()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$image = $this->application->uuid;
|
|
||||||
$output = instant_remote_process([
|
|
||||||
"docker inspect --format='{{.Config.Image}}' {$this->application->uuid}",
|
|
||||||
], $this->application->destination->server, throwError: false);
|
|
||||||
$current_tag = Str::of($output)->trim()->explode(":");
|
|
||||||
$this->current = data_get($current_tag, 1);
|
|
||||||
|
|
||||||
$output = instant_remote_process([
|
|
||||||
"docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}'",
|
|
||||||
], $this->application->destination->server);
|
|
||||||
$this->images = Str::of($output)->trim()->explode("\n")->filter(function ($item) use ($image) {
|
|
||||||
return Str::of($item)->contains($image);
|
|
||||||
})->map(function ($item) {
|
|
||||||
$item = Str::of($item)->explode('#');
|
|
||||||
if ($item[1] === $this->current) {
|
|
||||||
// $is_current = true;
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
'tag' => $item[1],
|
|
||||||
'created_at' => $item[2],
|
|
||||||
'is_current' => $is_current ?? null,
|
|
||||||
];
|
|
||||||
})->toArray();
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\PrivateKey;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Source extends Component
|
|
||||||
{
|
|
||||||
public $applicationId;
|
|
||||||
public Application $application;
|
|
||||||
public $private_keys;
|
|
||||||
protected $rules = [
|
|
||||||
'application.git_repository' => 'required',
|
|
||||||
'application.git_branch' => 'required',
|
|
||||||
'application.git_commit_sha' => 'nullable',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'application.git_repository' => 'repository',
|
|
||||||
'application.git_branch' => 'branch',
|
|
||||||
'application.git_commit_sha' => 'commit sha',
|
|
||||||
];
|
|
||||||
private function get_private_keys()
|
|
||||||
{
|
|
||||||
$this->private_keys = PrivateKey::whereTeamId(session('currentTeam')->id)->get()->reject(function ($key) {
|
|
||||||
return $key->id == $this->application->private_key_id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->get_private_keys();
|
|
||||||
}
|
|
||||||
public function setPrivateKey(int $private_key_id)
|
|
||||||
{
|
|
||||||
$this->application->private_key_id = $private_key_id;
|
|
||||||
$this->application->save();
|
|
||||||
$this->application->refresh();
|
|
||||||
$this->get_private_keys();
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
if (!$this->application->git_commit_sha) {
|
|
||||||
$this->application->git_commit_sha = 'HEAD';
|
|
||||||
}
|
|
||||||
$this->application->save();
|
|
||||||
$this->emit('success', 'Application source updated!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application\Storages;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Add extends Component
|
|
||||||
{
|
|
||||||
public $parameters;
|
|
||||||
public string $name;
|
|
||||||
public string $mount_path;
|
|
||||||
public string|null $host_path = null;
|
|
||||||
|
|
||||||
protected $listeners = ['clearAddStorage' => 'clear'];
|
|
||||||
protected $rules = [
|
|
||||||
'name' => 'required|string',
|
|
||||||
'mount_path' => 'required|string',
|
|
||||||
'host_path' => 'string|nullable',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'name' => 'name',
|
|
||||||
'mount_path' => 'mount',
|
|
||||||
'host_path' => 'host',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
$this->emitUp('submit', [
|
|
||||||
'name' => $this->name,
|
|
||||||
'mount_path' => $this->mount_path,
|
|
||||||
'host_path' => $this->host_path,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
public function clear()
|
|
||||||
{
|
|
||||||
$this->name = '';
|
|
||||||
$this->mount_path = '';
|
|
||||||
$this->host_path = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application\Storages;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\LocalPersistentVolume;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class All extends Component
|
|
||||||
{
|
|
||||||
public Application $application;
|
|
||||||
protected $listeners = ['refreshStorages', 'submit'];
|
|
||||||
public function refreshStorages()
|
|
||||||
{
|
|
||||||
$this->application->refresh();
|
|
||||||
}
|
|
||||||
public function submit($data)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
LocalPersistentVolume::create([
|
|
||||||
'name' => $data['name'],
|
|
||||||
'mount_path' => $data['mount_path'],
|
|
||||||
'host_path' => $data['host_path'],
|
|
||||||
'resource_id' => $this->application->id,
|
|
||||||
'resource_type' => Application::class,
|
|
||||||
]);
|
|
||||||
$this->application->refresh();
|
|
||||||
$this->emit('success', 'Storage added successfully');
|
|
||||||
$this->emit('clearAddStorage');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application\Storages;
|
|
||||||
|
|
||||||
use Livewire\Component;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class Show extends Component
|
|
||||||
{
|
|
||||||
public $storage;
|
|
||||||
public string|null $modalId = null;
|
|
||||||
protected $rules = [
|
|
||||||
'storage.name' => 'required|string',
|
|
||||||
'storage.mount_path' => 'required|string',
|
|
||||||
'storage.host_path' => 'string|nullable',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'name' => 'name',
|
|
||||||
'mount_path' => 'mount',
|
|
||||||
'host_path' => 'host',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->modalId = new Cuid2(7);
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
$this->storage->save();
|
|
||||||
$this->emit('success', 'Storage updated successfully');
|
|
||||||
}
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
$this->storage->delete();
|
|
||||||
$this->emit('refreshStorages');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project;
|
|
||||||
|
|
||||||
use App\Models\Environment;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class DeleteEnvironment extends Component
|
|
||||||
{
|
|
||||||
public array $parameters;
|
|
||||||
public int $environment_id;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
$this->validate([
|
|
||||||
'environment_id' => 'required|int',
|
|
||||||
]);
|
|
||||||
$environment = Environment::findOrFail($this->environment_id);
|
|
||||||
if ($environment->applications->count() > 0) {
|
|
||||||
return $this->emit('error', 'Environment has resources defined, please delete them first.');
|
|
||||||
}
|
|
||||||
$environment->delete();
|
|
||||||
return redirect()->route('project.show', ['project_uuid' => $this->parameters['project_uuid']]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project;
|
|
||||||
|
|
||||||
use App\Models\Project;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class DeleteProject extends Component
|
|
||||||
{
|
|
||||||
public array $parameters;
|
|
||||||
public int $project_id;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
$this->validate([
|
|
||||||
'project_id' => 'required|int',
|
|
||||||
]);
|
|
||||||
$project = Project::findOrFail($this->project_id);
|
|
||||||
if ($project->applications->count() > 0) {
|
|
||||||
return $this->emit('error', 'Project has resources defined, please delete them first.');
|
|
||||||
}
|
|
||||||
$project->delete();
|
|
||||||
return redirect()->route('projects');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project;
|
|
||||||
|
|
||||||
use App\Models\Project;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Edit extends Component
|
|
||||||
{
|
|
||||||
public Project $project;
|
|
||||||
protected $rules = [
|
|
||||||
'project.name' => 'required|min:3|max:255',
|
|
||||||
'project.description' => 'nullable|string|max:255',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
try {
|
|
||||||
$this->project->save();
|
|
||||||
$this->emit('saved');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\New;
|
|
||||||
|
|
||||||
use App\Models\Project;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class EmptyProject extends Component
|
|
||||||
{
|
|
||||||
public function createEmptyProject()
|
|
||||||
{
|
|
||||||
$project = Project::create([
|
|
||||||
'name' => generate_random_name(),
|
|
||||||
'team_id' => session('currentTeam')->id,
|
|
||||||
]);
|
|
||||||
return redirect()->route('project.show', ['project_uuid' => $project->uuid, 'environment_name' => 'production']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\New;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\GithubApp;
|
|
||||||
use App\Models\Project;
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\StandaloneDocker;
|
|
||||||
use App\Models\SwarmDocker;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class GithubPrivateRepository extends Component
|
|
||||||
{
|
|
||||||
public $github_apps;
|
|
||||||
public GithubApp $github_app;
|
|
||||||
public $parameters;
|
|
||||||
public $query;
|
|
||||||
public $type;
|
|
||||||
|
|
||||||
public int $selected_repository_id;
|
|
||||||
public int $selected_github_app_id;
|
|
||||||
public string $selected_repository_owner;
|
|
||||||
public string $selected_repository_repo;
|
|
||||||
|
|
||||||
public string $selected_branch_name = 'main';
|
|
||||||
|
|
||||||
public string $token;
|
|
||||||
|
|
||||||
protected int $page = 1;
|
|
||||||
|
|
||||||
public $repositories;
|
|
||||||
public int $total_repositories_count = 0;
|
|
||||||
|
|
||||||
public $branches;
|
|
||||||
public int $total_branches_count = 0;
|
|
||||||
|
|
||||||
public int $port = 3000;
|
|
||||||
public bool $is_static = false;
|
|
||||||
public string|null $publish_directory = null;
|
|
||||||
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
$this->query = request()->query();
|
|
||||||
$this->repositories = $this->branches = collect();
|
|
||||||
$this->github_apps = GithubApp::private();
|
|
||||||
}
|
|
||||||
protected function loadRepositoryByPage()
|
|
||||||
{
|
|
||||||
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100&page={$this->page}");
|
|
||||||
$json = $response->json();
|
|
||||||
if ($response->status() !== 200) {
|
|
||||||
return $this->emit('error', $json['message']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($json['total_count'] === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->total_repositories_count = $json['total_count'];
|
|
||||||
$this->repositories = $this->repositories->concat(collect($json['repositories']));
|
|
||||||
}
|
|
||||||
protected function loadBranchByPage()
|
|
||||||
{
|
|
||||||
Log::info('Loading page ' . $this->page);
|
|
||||||
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}");
|
|
||||||
$json = $response->json();
|
|
||||||
if ($response->status() !== 200) {
|
|
||||||
return $this->emit('error', $json['message']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->total_branches_count = count($json);
|
|
||||||
$this->branches = $this->branches->concat(collect($json));
|
|
||||||
}
|
|
||||||
public function loadRepositories($github_app_id)
|
|
||||||
{
|
|
||||||
$this->repositories = collect();
|
|
||||||
$this->page = 1;
|
|
||||||
$this->selected_github_app_id = $github_app_id;
|
|
||||||
$this->github_app = GithubApp::where('id', $github_app_id)->first();
|
|
||||||
$this->token = generate_github_installation_token($this->github_app);
|
|
||||||
$this->loadRepositoryByPage();
|
|
||||||
if ($this->repositories->count() < $this->total_repositories_count) {
|
|
||||||
while ($this->repositories->count() < $this->total_repositories_count) {
|
|
||||||
$this->page++;
|
|
||||||
$this->loadRepositoryByPage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->selected_repository_id = $this->repositories[0]['id'];
|
|
||||||
}
|
|
||||||
public function loadBranches()
|
|
||||||
{
|
|
||||||
$this->selected_repository_owner = $this->repositories->where('id', $this->selected_repository_id)->first()['owner']['login'];
|
|
||||||
$this->selected_repository_repo = $this->repositories->where('id', $this->selected_repository_id)->first()['name'];
|
|
||||||
$this->branches = collect();
|
|
||||||
$this->page = 1;
|
|
||||||
$this->loadBranchByPage();
|
|
||||||
if ($this->total_branches_count === 100) {
|
|
||||||
while ($this->total_branches_count === 100) {
|
|
||||||
$this->page++;
|
|
||||||
$this->loadBranchByPage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$destination_uuid = $this->query['destination'];
|
|
||||||
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
|
||||||
if (!$destination) {
|
|
||||||
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
|
|
||||||
}
|
|
||||||
if (!$destination) {
|
|
||||||
throw new \Exception('Destination not found. What?!');
|
|
||||||
}
|
|
||||||
$destination_class = $destination->getMorphClass();
|
|
||||||
|
|
||||||
|
|
||||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
|
||||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
|
||||||
|
|
||||||
$application = Application::create([
|
|
||||||
'name' => generate_application_name($this->selected_repository_owner . '/' . $this->selected_repository_repo, $this->selected_branch_name),
|
|
||||||
'repository_project_id' => $this->selected_repository_id,
|
|
||||||
'git_repository' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}",
|
|
||||||
'git_branch' => $this->selected_branch_name,
|
|
||||||
'build_pack' => 'nixpacks',
|
|
||||||
'ports_exposes' => $this->port,
|
|
||||||
'publish_directory' => $this->publish_directory,
|
|
||||||
'environment_id' => $environment->id,
|
|
||||||
'destination_id' => $destination->id,
|
|
||||||
'destination_type' => $destination_class,
|
|
||||||
'source_id' => $this->github_app->id,
|
|
||||||
'source_type' => $this->github_app->getMorphClass()
|
|
||||||
]);
|
|
||||||
$application->settings->is_static = $this->is_static;
|
|
||||||
$application->settings->save();
|
|
||||||
|
|
||||||
redirect()->route('project.application.configuration', [
|
|
||||||
'application_uuid' => $application->uuid,
|
|
||||||
'environment_name' => $environment->name,
|
|
||||||
'project_uuid' => $project->uuid,
|
|
||||||
]);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
if ($this->is_static) {
|
|
||||||
$this->port = 80;
|
|
||||||
$this->publish_directory = '/dist';
|
|
||||||
} else {
|
|
||||||
$this->port = 3000;
|
|
||||||
$this->publish_directory = null;
|
|
||||||
}
|
|
||||||
$this->emit('success', 'Application settings updated!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\New;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\GithubApp;
|
|
||||||
use App\Models\GitlabApp;
|
|
||||||
use App\Models\PrivateKey;
|
|
||||||
use App\Models\Project;
|
|
||||||
use App\Models\StandaloneDocker;
|
|
||||||
use App\Models\SwarmDocker;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Spatie\Url\Url;
|
|
||||||
|
|
||||||
class GithubPrivateRepositoryDeployKey extends Component
|
|
||||||
{
|
|
||||||
public $parameters;
|
|
||||||
public $query;
|
|
||||||
public $private_keys;
|
|
||||||
public int $private_key_id;
|
|
||||||
|
|
||||||
public int $port = 3000;
|
|
||||||
public string $type;
|
|
||||||
|
|
||||||
public bool $is_static = false;
|
|
||||||
public null|string $publish_directory = null;
|
|
||||||
|
|
||||||
public string $repository_url;
|
|
||||||
private object $repository_url_parsed;
|
|
||||||
public string $branch;
|
|
||||||
|
|
||||||
private GithubApp|GitlabApp $git_source;
|
|
||||||
private string $git_host;
|
|
||||||
private string $git_repository;
|
|
||||||
private string $git_branch;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'repository_url' => 'required|url',
|
|
||||||
'branch' => 'required|string',
|
|
||||||
'port' => 'required|numeric',
|
|
||||||
'is_static' => 'required|boolean',
|
|
||||||
'publish_directory' => 'nullable|string',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'repository_url' => 'Repository',
|
|
||||||
'branch' => 'Branch',
|
|
||||||
'port' => 'Port',
|
|
||||||
'is_static' => 'Is static',
|
|
||||||
'publish_directory' => 'Publish directory',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
if (isDev()) {
|
|
||||||
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
|
|
||||||
}
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
$this->query = request()->query();
|
|
||||||
$this->private_keys = PrivateKey::where('team_id', session('currentTeam')->id)->where('id', '!=', 0)->get();
|
|
||||||
}
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
if ($this->is_static) {
|
|
||||||
$this->port = 80;
|
|
||||||
$this->publish_directory = '/dist';
|
|
||||||
} else {
|
|
||||||
$this->port = 3000;
|
|
||||||
$this->publish_directory = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function setPrivateKey($private_key_id)
|
|
||||||
{
|
|
||||||
$this->private_key_id = $private_key_id;
|
|
||||||
}
|
|
||||||
private function get_git_source()
|
|
||||||
{
|
|
||||||
$this->repository_url_parsed = Url::fromString($this->repository_url);
|
|
||||||
$this->git_host = $this->repository_url_parsed->getHost();
|
|
||||||
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
|
|
||||||
if ($this->branch) {
|
|
||||||
$this->git_branch = $this->branch;
|
|
||||||
} else {
|
|
||||||
$this->git_branch = $this->repository_url_parsed->getSegment(4) ?? 'main';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->git_host == 'github.com') {
|
|
||||||
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
|
|
||||||
} elseif ($this->git_host == 'gitlab.com') {
|
|
||||||
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
|
|
||||||
} elseif ($this->git_host == 'bitbucket.org') {
|
|
||||||
// Not supported yet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
try {
|
|
||||||
$destination_uuid = $this->query['destination'];
|
|
||||||
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
|
||||||
if (!$destination) {
|
|
||||||
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
|
|
||||||
}
|
|
||||||
if (!$destination) {
|
|
||||||
throw new \Exception('Destination not found. What?!');
|
|
||||||
}
|
|
||||||
$destination_class = $destination->getMorphClass();
|
|
||||||
|
|
||||||
$this->get_git_source();
|
|
||||||
|
|
||||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
|
||||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
|
||||||
$application_init = [
|
|
||||||
'name' => generate_random_name(),
|
|
||||||
'git_repository' => $this->git_repository,
|
|
||||||
'git_branch' => $this->git_branch,
|
|
||||||
'git_full_url' => "git@$this->git_host:$this->git_repository.git",
|
|
||||||
'build_pack' => 'nixpacks',
|
|
||||||
'ports_exposes' => $this->port,
|
|
||||||
'publish_directory' => $this->publish_directory,
|
|
||||||
'environment_id' => $environment->id,
|
|
||||||
'destination_id' => $destination->id,
|
|
||||||
'destination_type' => $destination_class,
|
|
||||||
'private_key_id' => $this->private_key_id,
|
|
||||||
'source_id' => $this->git_source->id,
|
|
||||||
'source_type' => $this->git_source->getMorphClass()
|
|
||||||
];
|
|
||||||
$application = Application::create($application_init);
|
|
||||||
$application->settings->is_static = $this->is_static;
|
|
||||||
$application->settings->save();
|
|
||||||
|
|
||||||
return redirect()->route('project.application.configuration', [
|
|
||||||
'project_uuid' => $project->uuid,
|
|
||||||
'environment_name' => $environment->name,
|
|
||||||
'application_uuid' => $application->uuid,
|
|
||||||
]);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Project\New;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\GithubApp;
|
|
||||||
use App\Models\GitlabApp;
|
|
||||||
use App\Models\Project;
|
|
||||||
use App\Models\StandaloneDocker;
|
|
||||||
use App\Models\SwarmDocker;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Spatie\Url\Url;
|
|
||||||
|
|
||||||
class PublicGitRepository extends Component
|
|
||||||
{
|
|
||||||
public string $repository_url;
|
|
||||||
private object $repository_url_parsed;
|
|
||||||
|
|
||||||
public int $port = 3000;
|
|
||||||
public string $type;
|
|
||||||
public $parameters;
|
|
||||||
public $query;
|
|
||||||
|
|
||||||
public bool $branch_found = false;
|
|
||||||
public string $selected_branch = 'main';
|
|
||||||
public bool $is_static = false;
|
|
||||||
public string|null $publish_directory = null;
|
|
||||||
public string $git_branch = 'main';
|
|
||||||
public int $rate_limit_remaining = 0;
|
|
||||||
public $rate_limit_reset = 0;
|
|
||||||
|
|
||||||
private GithubApp|GitlabApp $git_source;
|
|
||||||
private string $git_host;
|
|
||||||
private string $git_repository;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'repository_url' => 'required|url',
|
|
||||||
'port' => 'required|numeric',
|
|
||||||
'is_static' => 'required|boolean',
|
|
||||||
'publish_directory' => 'nullable|string',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'repository_url' => 'repository',
|
|
||||||
'port' => 'port',
|
|
||||||
'is_static' => 'static',
|
|
||||||
'publish_directory' => 'publish directory',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
if (isDev()) {
|
|
||||||
$this->repository_url = 'https://github.com/coollabsio/coolify-examples';
|
|
||||||
$this->port = 3000;
|
|
||||||
}
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
$this->query = request()->query();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
if ($this->is_static) {
|
|
||||||
$this->port = 80;
|
|
||||||
$this->publish_directory = '/dist';
|
|
||||||
} else {
|
|
||||||
$this->port = 3000;
|
|
||||||
$this->publish_directory = null;
|
|
||||||
}
|
|
||||||
$this->emit('success', 'Application settings updated!');
|
|
||||||
}
|
|
||||||
private function get_branch()
|
|
||||||
{
|
|
||||||
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = git_api(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
|
|
||||||
$this->rate_limit_reset = Carbon::parse((int)$this->rate_limit_reset)->format('Y-M-d H:i:s');
|
|
||||||
$this->branch_found = true;
|
|
||||||
}
|
|
||||||
public function load_branch()
|
|
||||||
{
|
|
||||||
$this->branch_found = false;
|
|
||||||
$this->validate([
|
|
||||||
'repository_url' => 'required|url'
|
|
||||||
]);
|
|
||||||
$this->get_git_source();
|
|
||||||
try {
|
|
||||||
$this->get_branch();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->branch_found && $this->git_branch == 'main') {
|
|
||||||
try {
|
|
||||||
$this->git_branch = 'master';
|
|
||||||
$this->get_branch();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private function get_git_source()
|
|
||||||
{
|
|
||||||
$this->repository_url_parsed = Url::fromString($this->repository_url);
|
|
||||||
$this->git_host = $this->repository_url_parsed->getHost();
|
|
||||||
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
|
|
||||||
$this->git_branch = $this->repository_url_parsed->getSegment(4) ?? 'main';
|
|
||||||
|
|
||||||
if ($this->git_host == 'github.com') {
|
|
||||||
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
|
|
||||||
} elseif ($this->git_host == 'gitlab.com') {
|
|
||||||
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
|
|
||||||
} elseif ($this->git_host == 'bitbucket.org') {
|
|
||||||
// Not supported yet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->validate();
|
|
||||||
$destination_uuid = $this->query['destination'];
|
|
||||||
$project_uuid = $this->parameters['project_uuid'];
|
|
||||||
$environment_name = $this->parameters['environment_name'];
|
|
||||||
|
|
||||||
$this->get_git_source();
|
|
||||||
$this->git_branch = $this->selected_branch ?? $this->git_branch;
|
|
||||||
|
|
||||||
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
|
||||||
if (!$destination) {
|
|
||||||
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
|
|
||||||
}
|
|
||||||
if (!$destination) {
|
|
||||||
throw new \Exception('Destination not found. What?!');
|
|
||||||
}
|
|
||||||
$destination_class = $destination->getMorphClass();
|
|
||||||
|
|
||||||
$project = Project::where('uuid', $project_uuid)->first();
|
|
||||||
$environment = $project->load(['environments'])->environments->where('name', $environment_name)->first();
|
|
||||||
|
|
||||||
|
|
||||||
$application_init = [
|
|
||||||
'name' => generate_application_name($this->git_repository, $this->git_branch),
|
|
||||||
'git_repository' => $this->git_repository,
|
|
||||||
'git_branch' => $this->git_branch,
|
|
||||||
'build_pack' => 'nixpacks',
|
|
||||||
'ports_exposes' => $this->port,
|
|
||||||
'publish_directory' => $this->publish_directory,
|
|
||||||
'environment_id' => $environment->id,
|
|
||||||
'destination_id' => $destination->id,
|
|
||||||
'destination_type' => $destination_class,
|
|
||||||
'source_id' => $this->git_source->id,
|
|
||||||
'source_type' => $this->git_source->getMorphClass()
|
|
||||||
];
|
|
||||||
|
|
||||||
$application = Application::create($application_init);
|
|
||||||
$application->settings->is_static = $this->is_static;
|
|
||||||
$application->settings->save();
|
|
||||||
|
|
||||||
return redirect()->route('project.application.configuration', [
|
|
||||||
'project_uuid' => $project->uuid,
|
|
||||||
'environment_name' => $environment->name,
|
|
||||||
'application_uuid' => $application->uuid,
|
|
||||||
]);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e, that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire;
|
|
||||||
|
|
||||||
use App\Enums\ActivityTypes;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class RunCommand extends Component
|
|
||||||
{
|
|
||||||
public string $command;
|
|
||||||
public $server;
|
|
||||||
public $servers = [];
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'server' => 'required',
|
|
||||||
'command' => 'required',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'server' => 'server',
|
|
||||||
'command' => 'command',
|
|
||||||
];
|
|
||||||
public function mount($servers)
|
|
||||||
{
|
|
||||||
$this->servers = $servers;
|
|
||||||
$this->server = $servers[0]->uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function runCommand()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
try {
|
|
||||||
$activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true);
|
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Server;
|
|
||||||
|
|
||||||
use App\Actions\Server\InstallDocker;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
|
||||||
|
|
||||||
class Form extends Component
|
|
||||||
{
|
|
||||||
public Server $server;
|
|
||||||
public $uptime;
|
|
||||||
public $dockerVersion;
|
|
||||||
public string|null $wildcard_domain = null;
|
|
||||||
public int $cleanup_after_percentage;
|
|
||||||
public string|null $modalId = null;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'server.name' => 'required|min:6',
|
|
||||||
'server.description' => 'nullable',
|
|
||||||
'server.ip' => 'required',
|
|
||||||
'server.user' => 'required',
|
|
||||||
'server.port' => 'required',
|
|
||||||
'server.settings.is_reachable' => 'required',
|
|
||||||
'server.settings.is_part_of_swarm' => 'required',
|
|
||||||
'wildcard_domain' => 'nullable|url',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'server.name' => 'name',
|
|
||||||
'server.description' => 'description',
|
|
||||||
'server.ip' => 'ip',
|
|
||||||
'server.user' => 'user',
|
|
||||||
'server.port' => 'port',
|
|
||||||
'server.settings.is_reachable' => 'is reachable',
|
|
||||||
'server.settings.is_part_of_swarm' => 'is part of swarm'
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->modalId = new Cuid2(7);
|
|
||||||
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
|
||||||
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
|
|
||||||
}
|
|
||||||
public function installDocker()
|
|
||||||
{
|
|
||||||
$activity = resolve(InstallDocker::class)($this->server, session('currentTeam'));
|
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
|
||||||
}
|
|
||||||
public function validateServer()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->uptime = instant_remote_process(['uptime'], $this->server);
|
|
||||||
if ($this->uptime) {
|
|
||||||
$this->server->settings->is_reachable = true;
|
|
||||||
$this->server->settings->save();
|
|
||||||
} else {
|
|
||||||
$this->uptime = 'Server not reachable.';
|
|
||||||
throw new \Exception('Server not reachable.');
|
|
||||||
}
|
|
||||||
$this->dockerVersion = instant_remote_process(['docker version|head -2|grep -i version'], $this->server, false);
|
|
||||||
if (!$this->dockerVersion) {
|
|
||||||
$this->dockerVersion = 'Not installed.';
|
|
||||||
} else {
|
|
||||||
$this->server->settings->is_usable = true;
|
|
||||||
$this->server->settings->save();
|
|
||||||
$this->emit('proxyStatusUpdated');
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->server->settings->is_reachable = false;
|
|
||||||
$this->server->settings->is_usable = false;
|
|
||||||
$this->server->settings->save();
|
|
||||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function delete()
|
|
||||||
{
|
|
||||||
if (!$this->server->isEmpty()) {
|
|
||||||
$this->emit('error', 'Server has defined resources. Please delete them first.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->server->delete();
|
|
||||||
redirect()->route('server.all');
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
// $validation = Validator::make($this->server->toArray(), [
|
|
||||||
// 'ip' => [
|
|
||||||
// 'ip'
|
|
||||||
// ],
|
|
||||||
// ]);
|
|
||||||
// if ($validation->fails()) {
|
|
||||||
// foreach ($validation->errors()->getMessages() as $key => $value) {
|
|
||||||
// $this->addError("server.{$key}", $value[0]);
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
$this->server->settings->wildcard_domain = $this->wildcard_domain;
|
|
||||||
$this->server->settings->cleanup_after_percentage = $this->cleanup_after_percentage;
|
|
||||||
$this->server->settings->save();
|
|
||||||
$this->server->save();
|
|
||||||
$this->emit('success', 'Server updated successfully.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Server\New;
|
|
||||||
|
|
||||||
use App\Models\PrivateKey;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class ByIp extends Component
|
|
||||||
{
|
|
||||||
public $private_keys;
|
|
||||||
public int|null $private_key_id = null;
|
|
||||||
public $new_private_key_name;
|
|
||||||
public $new_private_key_description;
|
|
||||||
public $new_private_key_value;
|
|
||||||
|
|
||||||
public string $name;
|
|
||||||
public string|null $description = null;
|
|
||||||
public string $ip;
|
|
||||||
public string $user = 'root';
|
|
||||||
public int $port = 22;
|
|
||||||
public bool $is_part_of_swarm = false;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'name' => 'required|string',
|
|
||||||
'description' => 'nullable|string',
|
|
||||||
'ip' => 'required|ip',
|
|
||||||
'user' => 'required|string',
|
|
||||||
'port' => 'required|integer',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'name' => 'name',
|
|
||||||
'description' => 'description',
|
|
||||||
'ip' => 'ip',
|
|
||||||
'user' => 'user',
|
|
||||||
'port' => 'port',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->name = generate_random_name();
|
|
||||||
$this->private_key_id = $this->private_keys->first()->id;
|
|
||||||
}
|
|
||||||
public function setPrivateKey(string $private_key_id)
|
|
||||||
{
|
|
||||||
$this->private_key_id = $private_key_id;
|
|
||||||
}
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
$this->emit('success', 'Application settings updated!');
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
try {
|
|
||||||
if (!$this->private_key_id) {
|
|
||||||
return $this->emit('error', 'You must select a private key');
|
|
||||||
}
|
|
||||||
$server = Server::create([
|
|
||||||
'name' => $this->name,
|
|
||||||
'description' => $this->description,
|
|
||||||
'ip' => $this->ip,
|
|
||||||
'user' => $this->user,
|
|
||||||
'port' => $this->port,
|
|
||||||
'team_id' => session('currentTeam')->id,
|
|
||||||
'private_key_id' => $this->private_key_id,
|
|
||||||
]);
|
|
||||||
$server->settings->is_part_of_swarm = $this->is_part_of_swarm;
|
|
||||||
$server->settings->save();
|
|
||||||
return redirect()->route('server.show', $server->uuid);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Server;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Masmerise\Toaster\Toaster;
|
|
||||||
|
|
||||||
class PrivateKey extends Component
|
|
||||||
{
|
|
||||||
public Server $server;
|
|
||||||
public $privateKeys;
|
|
||||||
public $parameters;
|
|
||||||
|
|
||||||
public function checkConnection()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$uptime = instant_remote_process(['uptime'], $this->server);
|
|
||||||
if ($uptime) {
|
|
||||||
Toaster::success('Server is reachable with this private key.');
|
|
||||||
$this->server->settings->is_reachable = true;
|
|
||||||
$this->server->settings->is_usable = true;
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->server->settings->is_reachable = false;
|
|
||||||
$this->server->settings->is_usable = false;
|
|
||||||
$this->server->settings->save();
|
|
||||||
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function setPrivateKey($private_key_id)
|
|
||||||
{
|
|
||||||
$this->server->update([
|
|
||||||
'private_key_id' => $private_key_id
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Delete the old ssh mux file to force a new one to be created
|
|
||||||
Storage::disk('ssh-mux')->delete($this->server->muxFilename());
|
|
||||||
$this->server->refresh();
|
|
||||||
$this->checkConnection();
|
|
||||||
}
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->parameters = getRouteParameters();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Server;
|
|
||||||
|
|
||||||
use App\Actions\Proxy\CheckProxySettingsInSync;
|
|
||||||
use App\Enums\ProxyTypes;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Proxy extends Component
|
|
||||||
{
|
|
||||||
public Server $server;
|
|
||||||
|
|
||||||
public ProxyTypes $selectedProxy = ProxyTypes::TRAEFIK_V2;
|
|
||||||
public $proxy_settings = null;
|
|
||||||
public string|null $redirect_url = null;
|
|
||||||
|
|
||||||
protected $listeners = ['proxyStatusUpdated', 'saveConfiguration'];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->redirect_url = $this->server->proxy->redirect_url;
|
|
||||||
}
|
|
||||||
public function proxyStatusUpdated()
|
|
||||||
{
|
|
||||||
$this->server->refresh();
|
|
||||||
}
|
|
||||||
public function switchProxy()
|
|
||||||
{
|
|
||||||
$this->server->proxy = null;
|
|
||||||
$this->server->save();
|
|
||||||
$this->emit('proxyStatusUpdated');
|
|
||||||
}
|
|
||||||
public function setProxy(string $proxy_type)
|
|
||||||
{
|
|
||||||
$this->server->proxy->type = $proxy_type;
|
|
||||||
$this->server->proxy->status = 'exited';
|
|
||||||
$this->server->save();
|
|
||||||
$this->emit('proxyStatusUpdated');
|
|
||||||
}
|
|
||||||
public function stopProxy()
|
|
||||||
{
|
|
||||||
instant_remote_process([
|
|
||||||
"docker rm -f coolify-proxy",
|
|
||||||
], $this->server);
|
|
||||||
$this->server->proxy->status = 'exited';
|
|
||||||
$this->server->save();
|
|
||||||
$this->emit('proxyStatusUpdated');
|
|
||||||
}
|
|
||||||
public function saveConfiguration()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$proxy_path = config('coolify.proxy_config_path');
|
|
||||||
$this->proxy_settings = Str::of($this->proxy_settings)->trim()->value;
|
|
||||||
$docker_compose_yml_base64 = base64_encode($this->proxy_settings);
|
|
||||||
$this->server->proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
|
|
||||||
$this->server->proxy->redirect_url = $this->redirect_url;
|
|
||||||
$this->server->save();
|
|
||||||
|
|
||||||
instant_remote_process([
|
|
||||||
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
|
|
||||||
], $this->server);
|
|
||||||
$this->server->refresh();
|
|
||||||
setup_default_redirect_404(redirect_url: $this->server->proxy->redirect_url, server: $this->server);
|
|
||||||
$this->emit('success', 'Proxy configuration saved.');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function resetProxy()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->proxy_settings = resolve(CheckProxySettingsInSync::class)($this->server, true);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function checkProxySettingsInSync()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->proxy_settings = resolve(CheckProxySettingsInSync::class)($this->server);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return general_error_handler(err: $e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Server\Proxy;
|
|
||||||
|
|
||||||
use App\Actions\Proxy\StartProxy;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Str;
|
|
||||||
|
|
||||||
class Deploy extends Component
|
|
||||||
{
|
|
||||||
public Server $server;
|
|
||||||
public $proxy_settings = null;
|
|
||||||
protected $listeners = ['proxyStatusUpdated'];
|
|
||||||
public function proxyStatusUpdated()
|
|
||||||
{
|
|
||||||
$this->server->refresh();
|
|
||||||
}
|
|
||||||
public function deploy()
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
$this->server->proxy->last_applied_settings &&
|
|
||||||
$this->server->proxy->last_saved_settings !== $this->server->proxy->last_applied_settings
|
|
||||||
) {
|
|
||||||
$this->saveConfiguration($this->server);
|
|
||||||
}
|
|
||||||
$activity = resolve(StartProxy::class)($this->server);
|
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
|
||||||
}
|
|
||||||
public function stop()
|
|
||||||
{
|
|
||||||
instant_remote_process([
|
|
||||||
"docker rm -f coolify-proxy",
|
|
||||||
], $this->server);
|
|
||||||
$this->server->proxy->status = 'exited';
|
|
||||||
$this->server->save();
|
|
||||||
$this->emit('proxyStatusUpdated');
|
|
||||||
}
|
|
||||||
private function saveConfiguration(Server $server)
|
|
||||||
{
|
|
||||||
$this->emit('saveConfiguration', $server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Server\Proxy;
|
|
||||||
|
|
||||||
use App\Jobs\ProxyContainerStatusJob;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
|
|
||||||
class Status extends Component
|
|
||||||
{
|
|
||||||
public Server $server;
|
|
||||||
protected $listeners = ['proxyStatusUpdated'];
|
|
||||||
public function proxyStatusUpdated()
|
|
||||||
{
|
|
||||||
$this->server->refresh();
|
|
||||||
}
|
|
||||||
public function proxyStatus()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
dispatch_sync(new ProxyContainerStatusJob(
|
|
||||||
server: $this->server
|
|
||||||
));
|
|
||||||
$this->emit('proxyStatusUpdated');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
ray($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Livewire\Settings;
|
|
||||||
|
|
||||||
use App\Jobs\ProxyStartJob;
|
|
||||||
use App\Models\InstanceSettings as ModelsInstanceSettings;
|
|
||||||
use App\Models\Server;
|
|
||||||
use Livewire\Component;
|
|
||||||
use Spatie\Url\Url;
|
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
|
|
||||||
class Configuration extends Component
|
|
||||||
{
|
|
||||||
public ModelsInstanceSettings $settings;
|
|
||||||
public bool $do_not_track;
|
|
||||||
public bool $is_auto_update_enabled;
|
|
||||||
public bool $is_registration_enabled;
|
|
||||||
public bool $next_channel;
|
|
||||||
protected string $dynamic_config_path = '/data/coolify/proxy/dynamic';
|
|
||||||
protected Server $server;
|
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'settings.fqdn' => 'nullable',
|
|
||||||
'settings.resale_license' => 'nullable',
|
|
||||||
'settings.public_port_min' => 'required',
|
|
||||||
'settings.public_port_max' => 'required',
|
|
||||||
];
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'settings.fqdn' => 'FQDN',
|
|
||||||
'settings.resale_license' => 'Resale License',
|
|
||||||
'settings.public_port_min' => 'Public port min',
|
|
||||||
'settings.public_port_max' => 'Public port max',
|
|
||||||
];
|
|
||||||
public function mount()
|
|
||||||
{
|
|
||||||
$this->do_not_track = $this->settings->do_not_track;
|
|
||||||
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
|
|
||||||
$this->is_registration_enabled = $this->settings->is_registration_enabled;
|
|
||||||
$this->next_channel = $this->settings->next_channel;
|
|
||||||
}
|
|
||||||
public function instantSave()
|
|
||||||
{
|
|
||||||
$this->settings->do_not_track = $this->do_not_track;
|
|
||||||
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
|
|
||||||
$this->settings->is_registration_enabled = $this->is_registration_enabled;
|
|
||||||
$this->settings->next_channel = $this->next_channel;
|
|
||||||
$this->settings->save();
|
|
||||||
$this->emit('success', 'Settings updated!');
|
|
||||||
}
|
|
||||||
private function setup_instance_fqdn()
|
|
||||||
{
|
|
||||||
$file = "$this->dynamic_config_path/coolify.yaml";
|
|
||||||
if (empty($this->settings->fqdn)) {
|
|
||||||
remote_process([
|
|
||||||
"rm -f $file",
|
|
||||||
], $this->server);
|
|
||||||
} else {
|
|
||||||
$url = Url::fromString($this->settings->fqdn);
|
|
||||||
$host = $url->getHost();
|
|
||||||
$schema = $url->getScheme();
|
|
||||||
$traefik_dynamic_conf = [
|
|
||||||
'http' =>
|
|
||||||
[
|
|
||||||
'routers' =>
|
|
||||||
[
|
|
||||||
'coolify-http' =>
|
|
||||||
[
|
|
||||||
'entryPoints' => [
|
|
||||||
0 => 'http',
|
|
||||||
],
|
|
||||||
'service' => 'coolify',
|
|
||||||
'rule' => "Host(`{$host}`)",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'services' =>
|
|
||||||
[
|
|
||||||
'coolify' =>
|
|
||||||
[
|
|
||||||
'loadBalancer' =>
|
|
||||||
[
|
|
||||||
'servers' =>
|
|
||||||
[
|
|
||||||
0 =>
|
|
||||||
[
|
|
||||||
'url' => 'http://coolify:80',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($schema === 'https') {
|
|
||||||
$traefik_dynamic_conf['http']['routers']['coolify-http']['middlewares'] = [
|
|
||||||
0 => 'redirect-to-https@docker',
|
|
||||||
];
|
|
||||||
$traefik_dynamic_conf['http']['routers']['coolify-https'] = [
|
|
||||||
'entryPoints' => [
|
|
||||||
0 => 'https',
|
|
||||||
],
|
|
||||||
'service' => 'coolify',
|
|
||||||
'rule' => "Host(`{$host}`)",
|
|
||||||
'tls' => [
|
|
||||||
'certresolver' => 'letsencrypt',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
$this->save_configuration_to_disk($traefik_dynamic_conf, $file);
|
|
||||||
dispatch(new ProxyStartJob($this->server));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private function save_configuration_to_disk(array $traefik_dynamic_conf, string $file)
|
|
||||||
{
|
|
||||||
$yaml = Yaml::dump($traefik_dynamic_conf, 12, 2);
|
|
||||||
$yaml =
|
|
||||||
"# This file is automatically generated by Coolify.\n" .
|
|
||||||
"# Do not edit it manually (only if you know what are you doing).\n\n" .
|
|
||||||
$yaml;
|
|
||||||
|
|
||||||
$base64 = base64_encode($yaml);
|
|
||||||
remote_process([
|
|
||||||
"mkdir -p $this->dynamic_config_path",
|
|
||||||
"echo '$base64' | base64 -d > $file",
|
|
||||||
], $this->server);
|
|
||||||
|
|
||||||
if (config('app.env') == 'local') {
|
|
||||||
ray($yaml);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
$this->resetErrorBag();
|
|
||||||
if ($this->settings->public_port_min > $this->settings->public_port_max) {
|
|
||||||
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->validate();
|
|
||||||
$this->settings->save();
|
|
||||||
$this->server = Server::findOrFail(0);
|
|
||||||
$this->setup_instance_fqdn();
|
|
||||||
$this->emit('success', 'Instance settings updated successfully!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user