mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
Add Home service configuration and deployment setup
This commit is contained in:
15
.github/workflows/build.yml
vendored
15
.github/workflows/build.yml
vendored
@@ -40,6 +40,21 @@ jobs:
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./IsolatedVM/Dockerfile .
|
||||
|
||||
docker-build-home:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Preinstall
|
||||
run: npm run prerun
|
||||
|
||||
# build image for accounts service
|
||||
- name: build docker image
|
||||
run: sudo docker build -f ./Home/Dockerfile .
|
||||
|
||||
|
||||
docker-build-otel-collector:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
13
.github/workflows/compile.yml
vendored
13
.github/workflows/compile.yml
vendored
@@ -55,9 +55,20 @@ jobs:
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
- run: cd Common && npm install
|
||||
|
||||
- run: cd App && npm install && npm run compile && npm run dep-check
|
||||
|
||||
compile-home:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
- run: cd Common && npm install
|
||||
- run: cd Home && npm install && npm run compile && npm run dep-check
|
||||
|
||||
compile-copilot:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
|
||||
67
.github/workflows/release.yml
vendored
67
.github/workflows/release.yml
vendored
@@ -248,6 +248,69 @@ jobs:
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
home-docker-image-deploy:
|
||||
needs: [generate-build-number]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/home
|
||||
ghcr.io/oneuptime/home
|
||||
tags: |
|
||||
type=raw,value=release,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}},pattern={{version}},enable=true
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy isolated-vm.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./Home/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
|
||||
|
||||
|
||||
test-server-docker-image-deploy:
|
||||
needs: [generate-build-number]
|
||||
runs-on: ubuntu-latest
|
||||
@@ -1080,7 +1143,7 @@ jobs:
|
||||
|
||||
test-e2e-release-saas:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [copilot-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, ingestor-docker-image-deploy, isolated-vm-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
|
||||
needs: [copilot-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, ingestor-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
@@ -1133,7 +1196,7 @@ jobs:
|
||||
test-e2e-release-self-hosted:
|
||||
runs-on: ubuntu-latest
|
||||
# After all the jobs runs
|
||||
needs: [copilot-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, ingestor-docker-image-deploy, isolated-vm-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
|
||||
needs: [copilot-docker-image-deploy, llm-docker-image-deploy, accounts-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, dashboard-docker-image-deploy, haraka-docker-image-deploy, ingestor-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, otel-collector-docker-image-deploy, probe-docker-image-deploy, status-page-docker-image-deploy, test-docker-image-deploy, test-server-docker-image-deploy, publish-npm-packages, e2e-docker-image-deploy, helm-chart-deploy, generate-build-number, nginx-docker-image-deploy]
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
|
||||
65
.github/workflows/test-release.yaml
vendored
65
.github/workflows/test-release.yaml
vendored
@@ -412,6 +412,69 @@ jobs:
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
home-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
oneuptime/home
|
||||
ghcr.io/oneuptime/home
|
||||
tags: |
|
||||
type=raw,value=test,enable=true
|
||||
type=semver,value=7.0.${{needs.generate-build-number.outputs.build_number}}-test,pattern={{version}},enable=true
|
||||
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Generate Dockerfile from Dockerfile.tpl
|
||||
run: npm run prerun
|
||||
|
||||
# Build and deploy isolated-vm.
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
file: ./Home/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.sha }}
|
||||
APP_VERSION=7.0.${{needs.generate-build-number.outputs.build_number}}
|
||||
|
||||
|
||||
|
||||
status-page-docker-image-deploy:
|
||||
needs: generate-build-number
|
||||
runs-on: ubuntu-latest
|
||||
@@ -1028,7 +1091,7 @@ jobs:
|
||||
|
||||
test-helm-chart:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [llm-docker-image-deploy, copilot-docker-image-deploy, isolated-vm-docker-image-deploy, test-server-docker-image-deploy, test-docker-image-deploy, ingestor-docker-image-deploy, probe-docker-image-deploy, haraka-docker-image-deploy, dashboard-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, accounts-docker-image-deploy, otel-collector-docker-image-deploy, status-page-docker-image-deploy, nginx-docker-image-deploy, e2e-docker-image-deploy]
|
||||
needs: [llm-docker-image-deploy, copilot-docker-image-deploy, isolated-vm-docker-image-deploy, home-docker-image-deploy, test-server-docker-image-deploy, test-docker-image-deploy, ingestor-docker-image-deploy, probe-docker-image-deploy, haraka-docker-image-deploy, dashboard-docker-image-deploy, admin-dashboard-docker-image-deploy, app-docker-image-deploy, accounts-docker-image-deploy, otel-collector-docker-image-deploy, status-page-docker-image-deploy, nginx-docker-image-deploy, e2e-docker-image-deploy]
|
||||
env:
|
||||
CI_PIPELINE_ID: ${{github.run_number}}
|
||||
steps:
|
||||
|
||||
14
.vscode/launch.json
vendored
14
.vscode/launch.json
vendored
@@ -63,6 +63,20 @@
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/Home",
|
||||
"name": "Home: Debug with Docker",
|
||||
"port": 9212,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/TestServer",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@oneuptime/app",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"main": "Index.ts",
|
||||
"scripts": {
|
||||
"start": "node --require ts-node/register Index.ts",
|
||||
"compile": "tsc",
|
||||
|
||||
@@ -100,6 +100,12 @@ export const IsolatedVMHostname: Hostname = Hostname.fromString(
|
||||
}`,
|
||||
);
|
||||
|
||||
export const HomeHostname: Hostname = Hostname.fromString(
|
||||
`${process.env["SERVER_HOME_HOSTNAME"] || "localhost"}:${
|
||||
process.env["HOME_PORT"] || 80
|
||||
}`,
|
||||
);
|
||||
|
||||
export const AccountsHostname: Hostname = Hostname.fromString(
|
||||
`${process.env["SERVER_ACCOUNTS_HOSTNAME"] || "localhost"}:${
|
||||
process.env["ACCOUNTS_PORT"] || 80
|
||||
|
||||
@@ -48,6 +48,8 @@ Usage:
|
||||
value: {{ $.Release.Name }}-accounts.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
|
||||
- name: SERVER_ISOLATED_VM_HOSTNAME
|
||||
value: {{ $.Release.Name }}-isolated-vm.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
|
||||
- name: SERVER_HOME_HOSTNAME
|
||||
value: {{ $.Release.Name }}-home.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
|
||||
- name: SERVER_APP_HOSTNAME
|
||||
value: {{ $.Release.Name }}-app.{{ $.Release.Namespace }}.svc.{{ $.Values.global.clusterDomain }}
|
||||
- name: SERVER_INGESTOR_HOSTNAME
|
||||
@@ -75,6 +77,8 @@ Usage:
|
||||
value: {{ $.Values.port.accounts | squote }}
|
||||
- name: ISOLATED_VM_PORT
|
||||
value: {{ $.Values.port.isolatedVM | squote }}
|
||||
- name: HOME_PORT
|
||||
value: {{ $.Values.port.home | squote }}
|
||||
- name: STATUS_PAGE_PORT
|
||||
value: {{ $.Values.port.statusPage | squote }}
|
||||
- name: DASHBOARD_PORT
|
||||
|
||||
85
HelmChart/Public/oneuptime/templates/home.yaml
Normal file
85
HelmChart/Public/oneuptime/templates/home.yaml
Normal file
@@ -0,0 +1,85 @@
|
||||
# OneUptime Home Deployment
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ printf "%s-%s" $.Release.Name "home" }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
app: {{ printf "%s-%s" $.Release.Name "home" }}
|
||||
app.kubernetes.io/part-of: oneuptime
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
appname: oneuptime
|
||||
date: "{{ now | unixEpoch }}"
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ printf "%s-%s" $.Release.Name "home" }}
|
||||
replicas: {{ $.Values.deployment.replicaCount }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ printf "%s-%s" $.Release.Name "home" }}
|
||||
date: "{{ now | unixEpoch }}"
|
||||
appname: oneuptime
|
||||
spec:
|
||||
{{- if $.Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml $.Values.imagePullSecrets | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if $.Values.podSecurityContext }}
|
||||
securityContext: {{- $.Values.podSecurityContext | toYaml | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if $.Values.affinity }}
|
||||
affinity: {{- $.Values.affinity | toYaml | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if $.Values.tolerations }}
|
||||
tolerations: {{- $.Values.tolerations | toYaml | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if $.Values.nodeSelector }}
|
||||
nodeSelector: {{- $.Values.nodeSelector | toYaml | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- image: {{ printf "%s/%s/%s:%s" $.Values.image.registry $.Values.image.repository "home" $.Values.image.tag }}
|
||||
name: {{ printf "%s-%s" $.Release.Name "home" }}
|
||||
# Liveness probe
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /status/live
|
||||
port: {{ $.Values.port.home }}
|
||||
initialDelaySeconds: 300
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 30
|
||||
# Readyness Probe
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /status/ready
|
||||
port: {{ $.Values.port.home }}
|
||||
initialDelaySeconds: 300
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 30
|
||||
{{- if $.Values.containerSecurityContext }}
|
||||
securityContext: {{- $.Values.containerSecurityContext | toYaml | nindent 12 }}
|
||||
{{- end }}
|
||||
imagePullPolicy: {{ $.Values.image.pullPolicy }}
|
||||
env:
|
||||
{{- include "oneuptime.env.common" . | nindent 12 }}
|
||||
{{- include "oneuptime.env.commonServer" . | nindent 12 }}
|
||||
{{- include "oneuptime.env.oneuptimeSecret" . | nindent 12 }}
|
||||
ports:
|
||||
- containerPort: {{ $.Values.port.home }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
restartPolicy: {{ $.Values.image.restartPolicy }}
|
||||
|
||||
---
|
||||
|
||||
# OneUptime app Service
|
||||
{{- $homePorts := dict "port" $.Values.port.home -}}
|
||||
{{- $homeServiceArgs := dict "ServiceName" "home" "Ports" $homePorts "Release" $.Release "Values" $.Values -}}
|
||||
{{- include "oneuptime.service" $homeServiceArgs }}
|
||||
---
|
||||
|
||||
# OneUptime app autoscaler
|
||||
{{- $homeAutoScalerArgs := dict "ServiceName" "home" "Release" $.Release "Values" $.Values -}}
|
||||
{{- include "oneuptime.autoscaler" $homeAutoScalerArgs }}
|
||||
---
|
||||
@@ -207,6 +207,7 @@ port:
|
||||
otelCollectorGrpc: 4317
|
||||
otelCollectorHttp: 4318
|
||||
isolatedVM: 4572
|
||||
home: 1444
|
||||
|
||||
|
||||
testServer:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@oneuptime/home",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"main": "Index.ts",
|
||||
"scripts": {
|
||||
"start": "node --require ts-node/register Index.ts",
|
||||
"compile": "tsc",
|
||||
|
||||
@@ -22,6 +22,10 @@ upstream isolated-vm {
|
||||
server ${SERVER_ISOLATED_VM_HOSTNAME}:${ISOLATED_VM_PORT} weight=10 max_fails=3 fail_timeout=30s;
|
||||
}
|
||||
|
||||
upstream home {
|
||||
server ${SERVER_HOME_HOSTNAME}:${HOME_PORT} weight=10 max_fails=3 fail_timeout=30s;
|
||||
}
|
||||
|
||||
upstream status-page {
|
||||
server ${SERVER_STATUS_PAGE_HOSTNAME}:${STATUS_PAGE_PORT} weight=10 max_fails=3 fail_timeout=30s;
|
||||
}
|
||||
@@ -384,7 +388,7 @@ server {
|
||||
|
||||
# If billing_enabled is true then proxy to home otherwise to dashboard because we dont need marketing paages for on-prem install.
|
||||
if ($billing_enabled = true) {
|
||||
proxy_pass http://app;
|
||||
proxy_pass http://home;
|
||||
}
|
||||
|
||||
if ($billing_enabled != true) {
|
||||
|
||||
@@ -34,9 +34,11 @@ x-common-variables: &common-variables
|
||||
SERVER_ADMIN_DASHBOARD_HOSTNAME: admin-dashboard
|
||||
SERVER_OTEL_COLLECTOR_HOSTNAME: otel-collector
|
||||
SERVER_ISOLATED_VM_HOSTNAME: isolated-vm
|
||||
SERVER_HOME_HOSTNAME: home
|
||||
|
||||
#Ports. Usually they don't need to change.
|
||||
APP_PORT: ${APP_PORT}
|
||||
HOME_PORT: ${HOME_PORT}
|
||||
INGESTOR_PORT: ${INGESTOR_PORT}
|
||||
PROBE_PORT: ${PROBE_PORT}
|
||||
TEST_SERVER_PORT: ${TEST_SERVER_PORT}
|
||||
@@ -274,6 +276,18 @@ services:
|
||||
options:
|
||||
max-size: "1000m"
|
||||
|
||||
home:
|
||||
networks:
|
||||
- oneuptime
|
||||
restart: always
|
||||
environment:
|
||||
<<: *common-server-variables
|
||||
PORT: ${HOME_PORT}
|
||||
logging:
|
||||
driver: "local"
|
||||
options:
|
||||
max-size: "1000m"
|
||||
|
||||
probe-1:
|
||||
networks:
|
||||
- oneuptime
|
||||
|
||||
@@ -160,6 +160,24 @@ services:
|
||||
dockerfile: ./TestServer/Dockerfile
|
||||
|
||||
|
||||
home:
|
||||
volumes:
|
||||
- ./Home:/usr/src/app
|
||||
# Use node modules of the container and not host system.
|
||||
# https://stackoverflow.com/questions/29181032/add-a-volume-to-docker-but-exclude-a-sub-folder
|
||||
- /usr/src/app/node_modules/
|
||||
- ./Common:/usr/src/Common
|
||||
- /usr/src/Common/node_modules/
|
||||
extends:
|
||||
file: ./docker-compose.base.yml
|
||||
service: home
|
||||
ports:
|
||||
- '9212:9229' # Debugging port.
|
||||
build:
|
||||
network: host
|
||||
context: .
|
||||
dockerfile: ./Home/Dockerfile
|
||||
|
||||
app:
|
||||
volumes:
|
||||
- ./App:/usr/src/app
|
||||
@@ -167,10 +185,7 @@ services:
|
||||
# https://stackoverflow.com/questions/29181032/add-a-volume-to-docker-but-exclude-a-sub-folder
|
||||
- /usr/src/app/node_modules/
|
||||
- ./Common:/usr/src/Common
|
||||
|
||||
- /usr/src/Common/node_modules/
|
||||
|
||||
|
||||
extends:
|
||||
file: ./docker-compose.base.yml
|
||||
service: app
|
||||
|
||||
@@ -65,6 +65,12 @@ services:
|
||||
file: ./docker-compose.base.yml
|
||||
service: app
|
||||
|
||||
home:
|
||||
image: oneuptime/home:${APP_TAG}
|
||||
extends:
|
||||
file: ./docker-compose.base.yml
|
||||
service: home
|
||||
|
||||
probe-1:
|
||||
image: oneuptime/probe:${APP_TAG}
|
||||
extends:
|
||||
|
||||
Reference in New Issue
Block a user