docker release
This commit is contained in:
117
bkp/azdo-tickets-between-branches.sh
Executable file
117
bkp/azdo-tickets-between-branches.sh
Executable file
@@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Get all work items (tickets) between two branches in Azure DevOps.
|
||||||
|
#
|
||||||
|
# Reports tickets from TWO sources:
|
||||||
|
# 1. Formally linked work items (git commit <-> work item links)
|
||||||
|
# 2. Ticket numbers scraped from commit messages (this repo references
|
||||||
|
# tickets in text far more than it formally links them)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./azdo-tickets-between-branches.sh <baseBranch> <targetBranch>
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# ./azdo-tickets-between-branches.sh master release/5.4.0
|
||||||
|
#
|
||||||
|
# Requires: curl, jq
|
||||||
|
# Auth: set a Personal Access Token in AZDO_PAT (scopes: Code Read + Work Items Read).
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ---- Config (override via env vars) -----------------------------------------
|
||||||
|
# Project collection base URL (host + collection), e.g. old visualstudio.com style.
|
||||||
|
COLLECTION_URL="${AZDO_COLLECTION_URL:-https://flashmobilevending.visualstudio.com/DefaultCollection}"
|
||||||
|
PROJECT="${AZDO_PROJECT:-GLU}"
|
||||||
|
REPO="${AZDO_REPO:-glu-flash-console}"
|
||||||
|
PAT="${AZDO_PAT:-}"
|
||||||
|
API_VERSION="7.1"
|
||||||
|
# Regex for ticket numbers in commit messages (this project uses 6-digit IDs).
|
||||||
|
TICKET_REGEX="${AZDO_TICKET_REGEX:-[0-9]{6}}"
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
BASE="${1:-}"
|
||||||
|
TARGET="${2:-}"
|
||||||
|
|
||||||
|
if [[ -z "$BASE" || -z "$TARGET" ]]; then
|
||||||
|
echo "Usage: $0 <baseBranch> <targetBranch>" >&2
|
||||||
|
echo "Example: $0 master release/5.4.0" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$PAT" ]]; then
|
||||||
|
echo "Error: set AZDO_PAT to a Personal Access Token (Code Read + Work Items Read)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for cmd in curl jq; do
|
||||||
|
command -v "$cmd" >/dev/null 2>&1 || { echo "Error: '$cmd' is required." >&2; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
GIT_URL="${COLLECTION_URL}/${PROJECT}/_apis/git/repositories/${REPO}"
|
||||||
|
WIT_URL="${COLLECTION_URL}/${PROJECT}/_apis/wit/workitems"
|
||||||
|
|
||||||
|
# ---- Step 1: commits on TARGET but not on BASE, with linked work items -------
|
||||||
|
commits_json=$(curl -sf -u ":${PAT}" \
|
||||||
|
"${GIT_URL}/commitsbatch?\$top=1000&api-version=${API_VERSION}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"itemVersion\": {\"versionType\":\"branch\",\"version\":\"${BASE}\"},
|
||||||
|
\"compareVersion\": {\"versionType\":\"branch\",\"version\":\"${TARGET}\"},
|
||||||
|
\"includeWorkItems\": true
|
||||||
|
}")
|
||||||
|
|
||||||
|
# 1a. Formally linked work item IDs
|
||||||
|
linked_ids=$(echo "$commits_json" | jq -r '[.value[].workItems[]?.id] | unique | .[]' || true)
|
||||||
|
|
||||||
|
# 1b. Ticket numbers scraped from commit messages.
|
||||||
|
# Strip "Merged PR NNNNN" first so PR ids aren't mistaken for tickets.
|
||||||
|
scraped_ids=$(echo "$commits_json" \
|
||||||
|
| jq -r '.value[].comment' \
|
||||||
|
| sed -E 's/[Mm]erged PR [0-9]+//g' \
|
||||||
|
| grep -oE "$TICKET_REGEX" \
|
||||||
|
| sort -u || true)
|
||||||
|
|
||||||
|
# Union of both sources
|
||||||
|
all_ids=$(printf '%s\n%s\n' "$linked_ids" "$scraped_ids" | grep -E '^[0-9]+$' | sort -un || true)
|
||||||
|
|
||||||
|
commit_count=$(echo "$commits_json" | jq '.value | length')
|
||||||
|
echo "Comparing '${TARGET}' against '${BASE}' (${commit_count} commits ahead)"
|
||||||
|
echo " Formally linked: $(echo "$linked_ids" | grep -c . || true)"
|
||||||
|
echo " Scraped from msgs: $(echo "$scraped_ids" | grep -c . || true)"
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [[ -z "$all_ids" ]]; then
|
||||||
|
echo "No tickets found (no links and no ticket numbers in commit messages)."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- Step 2: hydrate work item details --------------------------------------
|
||||||
|
ids_csv=$(echo "$all_ids" | paste -sd, -)
|
||||||
|
|
||||||
|
http_status=$(curl -s -o /tmp/azdo_wit.json -w "%{http_code}" -u ":${PAT}" \
|
||||||
|
"${WIT_URL}?ids=${ids_csv}&fields=System.Id,System.WorkItemType,System.State,System.Title&errorPolicy=omit&api-version=${API_VERSION}")
|
||||||
|
|
||||||
|
if [[ "$http_status" != "200" ]]; then
|
||||||
|
echo "Warning: could not fetch work item details (HTTP ${http_status})." >&2
|
||||||
|
if [[ "$http_status" == "401" || "$http_status" == "403" ]]; then
|
||||||
|
echo " Your PAT is likely missing the 'Work Items (Read)' scope." >&2
|
||||||
|
fi
|
||||||
|
echo " Falling back to ticket IDs only:" >&2
|
||||||
|
echo
|
||||||
|
echo "$all_ids"
|
||||||
|
echo
|
||||||
|
echo "View any of them at: ${COLLECTION_URL}/${PROJECT}/_workitems/edit/<id>"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# errorPolicy=omit returns null entries for ids that aren't real work items;
|
||||||
|
# filter those out so scraped false-positives disappear.
|
||||||
|
{
|
||||||
|
printf 'ID\tTYPE\tSTATE\tTITLE\n'
|
||||||
|
jq -r '.value[] | select(. != null)
|
||||||
|
| [ (.fields["System.Id"]|tostring),
|
||||||
|
.fields["System.WorkItemType"],
|
||||||
|
.fields["System.State"],
|
||||||
|
(.fields["System.Title"] // "") ]
|
||||||
|
| @tsv' /tmp/azdo_wit.json
|
||||||
|
} | column -t -s $'\t'
|
||||||
54
bkp/docker-compose copy.yml
Normal file
54
bkp/docker-compose copy.yml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8
|
||||||
|
container_name: fennec-mysql
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: password
|
||||||
|
MYSQL_DATABASE: fennecpro
|
||||||
|
volumes:
|
||||||
|
- mysql-data:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-ppassword"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 30s
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: ../../fennec-hub-multi-tenant-shared-db/Dockerfile
|
||||||
|
container_name: fennec-backend
|
||||||
|
environment:
|
||||||
|
SPRING_PROFILES_ACTIVE: custom
|
||||||
|
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/fennecpro?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
|
||||||
|
SPRING_DATASOURCE_USERNAME: root
|
||||||
|
SPRING_DATASOURCE_PASSWORD: password
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
expose:
|
||||||
|
- "8080"
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ../../fennec-hub-angular-ui
|
||||||
|
dockerfile: ../../fennec-hub-angular-ui/Dockerfile
|
||||||
|
container_name: fennec-frontend
|
||||||
|
ports:
|
||||||
|
- "8888:80"
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
fennec:
|
||||||
|
driver: bridge
|
||||||
46
bkp/docker-compose-latest.yml
Normal file
46
bkp/docker-compose-latest.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: ../../fennec-hub-multi-tenant-shared-db/Dockerfile
|
||||||
|
container_name: fennec-backend
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
environment:
|
||||||
|
SPRING_PROFILES_ACTIVE: custom
|
||||||
|
SPRING_DATASOURCE_URL: jdbc:mysql://host.docker.internal:3306/fennecpro?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
|
||||||
|
SPRING_DATASOURCE_USERNAME: root
|
||||||
|
SPRING_DATASOURCE_PASSWORD: password
|
||||||
|
# Honor X-Forwarded-* from nginx so Spring reconstructs the original URL
|
||||||
|
# (http://localhost) instead of seeing http://backend:8080.
|
||||||
|
SERVER_FORWARD_HEADERS_STRATEGY: framework
|
||||||
|
# CORS allow-list — frontend served via nginx on http://localhost (port 80).
|
||||||
|
# Keep :4200 so the non-dockerized Angular dev server still works.
|
||||||
|
FENNEC_HUB_SECURITY_CORS_ALLOWED_ORIGINS: "http://localhost,http://localhost:4200,https://hub.fennecsm.com"
|
||||||
|
ports:
|
||||||
|
- "9999:8080"
|
||||||
|
volumes:
|
||||||
|
- /home/fennec/hub:/home/fennec/hub
|
||||||
|
#expose:
|
||||||
|
# - "8080"
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ../../fennec-hub-angular-ui
|
||||||
|
dockerfile: ../../fennec-hub-angular-ui/Dockerfile
|
||||||
|
container_name: fennec-frontend
|
||||||
|
ports:
|
||||||
|
- "8888:80"
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
fennec:
|
||||||
|
driver: bridge
|
||||||
47
bkp/docker-compose-noui.yml
Normal file
47
bkp/docker-compose-noui.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: ../../fennec-hub-multi-tenant-shared-db/Dockerfile
|
||||||
|
container_name: fennec-backend
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
environment:
|
||||||
|
SPRING_PROFILES_ACTIVE: custom
|
||||||
|
SPRING_DATASOURCE_URL: jdbc:mysql://host.docker.internal:3306/fennecpro?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
|
||||||
|
SPRING_DATASOURCE_USERNAME: root
|
||||||
|
SPRING_DATASOURCE_PASSWORD: Yamm@230371
|
||||||
|
# Honor X-Forwarded-* from nginx so Spring reconstructs the original URL
|
||||||
|
# (http://localhost) instead of seeing http://backend:8080.
|
||||||
|
SERVER_FORWARD_HEADERS_STRATEGY: framework
|
||||||
|
# CORS allow-list — frontend served via nginx on http://localhost (port 80).
|
||||||
|
# Keep :4200 so the non-dockerized Angular dev server still works.
|
||||||
|
FENNEC_HUB_SECURITY_CORS_ALLOWED_ORIGINS: "http://localhost,http://localhost:4200,https://hub.fennecsm.com"
|
||||||
|
ports:
|
||||||
|
- "9999:8080"
|
||||||
|
volumes:
|
||||||
|
- /home/fennec/hub:/home/fennec/hub
|
||||||
|
#expose:
|
||||||
|
# - "8080"
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
# frontend:
|
||||||
|
# build:
|
||||||
|
# context: ./fennec-hub-angular-ui
|
||||||
|
# dockerfile: Dockerfile
|
||||||
|
# container_name: fennec-frontend
|
||||||
|
# ports:
|
||||||
|
# - "8888:80"
|
||||||
|
# depends_on:
|
||||||
|
# - backend
|
||||||
|
# networks:
|
||||||
|
#wq! - fennec
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
fennec:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
57
bkp/docker-compose.yml
Normal file
57
bkp/docker-compose.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: ../../fennec-hub-multi-tenant-shared-db/Dockerfile
|
||||||
|
container_name: fennec-backend
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
environment:
|
||||||
|
SPRING_PROFILES_ACTIVE: custom
|
||||||
|
SPRING_DATASOURCE_URL: jdbc:mysql://host.docker.internal:3306/fennecpro?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
|
||||||
|
SPRING_DATASOURCE_USERNAME: root
|
||||||
|
SPRING_DATASOURCE_PASSWORD: Yamm@230371
|
||||||
|
# Honor X-Forwarded-* from nginx so Spring reconstructs the original URL
|
||||||
|
# (http://localhost) instead of seeing http://backend:8080.
|
||||||
|
SERVER_FORWARD_HEADERS_STRATEGY: framework
|
||||||
|
# CORS allow-list — frontend served via nginx on http://localhost (port 80).
|
||||||
|
# Keep :4200 so the non-dockerized Angular dev server still works.
|
||||||
|
FENNEC_HUB_SECURITY_CORS_ALLOWED_ORIGINS: "http://localhost,http://localhost:4200,https://hub.fennecsm.com,https://ecom.fennecsm.com"
|
||||||
|
ports:
|
||||||
|
- "9999:8080"
|
||||||
|
volumes:
|
||||||
|
- /home/fennec/hub:/home/fennec/hub
|
||||||
|
#expose:
|
||||||
|
# - "8080"
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ../../fennec-hub-angular-ui
|
||||||
|
dockerfile: ../../fennec-hub-angular-ui/Dockerfile
|
||||||
|
container_name: fennec-frontend
|
||||||
|
ports:
|
||||||
|
- "8888:80"
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
frontendcomm:
|
||||||
|
build:
|
||||||
|
context: ../../fennec-hub-commerce
|
||||||
|
dockerfile: ../../fennec-hub-commerce/Dockerfile
|
||||||
|
container_name: fennec-frontendcomm
|
||||||
|
ports:
|
||||||
|
- "8889:80"
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
volumes:
|
||||||
|
mysql-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
fennec:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
70
bkp/docker-compose.yml.bkp
Normal file
70
bkp/docker-compose.yml.bkp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8
|
||||||
|
container_name: fennec-mysql
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: password
|
||||||
|
MYSQL_DATABASE: fennecpro
|
||||||
|
MYSQL_INNODB_DEFAULT_ROW_FORMAT: DYNAMIC # ← add this
|
||||||
|
command:
|
||||||
|
- --innodb-default-row-format=dynamic # ← add this
|
||||||
|
- --innodb-file-per-table=1 # ← add this
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- mysql-data:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-ppassword"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 30s
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: fennec-hub-multi-tenant-shared-db/Dockerfile
|
||||||
|
container_name: fennec-backend
|
||||||
|
environment:
|
||||||
|
SPRING_PROFILES_ACTIVE: custom
|
||||||
|
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/fennecpro?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
|
||||||
|
SPRING_DATASOURCE_USERNAME: root
|
||||||
|
SPRING_DATASOURCE_PASSWORD: password
|
||||||
|
# Honor X-Forwarded-* from nginx so Spring reconstructs the original URL
|
||||||
|
# (http://localhost) instead of seeing http://backend:8080.
|
||||||
|
SERVER_FORWARD_HEADERS_STRATEGY: framework
|
||||||
|
# CORS allow-list — frontend served via nginx on http://localhost (port 80).
|
||||||
|
# Keep :4200 so the non-dockerized Angular dev server still works.
|
||||||
|
FENNEC_HUB_SECURITY_CORS_ALLOWED_ORIGINS: "http://localhost,http://localhost:4200,https://hub.fennecsm.com"
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
ports:
|
||||||
|
- "9999:8080"
|
||||||
|
volumes:
|
||||||
|
- /home/fennec/hub:/home/fennec/hub
|
||||||
|
#expose:
|
||||||
|
# - "8080"
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ./fennec-hub-angular-ui
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: fennec-frontend
|
||||||
|
ports:
|
||||||
|
- "8888:80"
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
networks:
|
||||||
|
- fennec
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
fennec:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
81
bkp/fennec.sh
Normal file
81
bkp/fennec.sh
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BASE_DIR="/home/fennec-hub"
|
||||||
|
|
||||||
|
update() {
|
||||||
|
echo "========================================"
|
||||||
|
echo "Updating Git repositories..."
|
||||||
|
echo "========================================"
|
||||||
|
|
||||||
|
for repo in \
|
||||||
|
fennec-hub-platfrom \
|
||||||
|
fennec-hub-multi-tenant-shared-db \
|
||||||
|
fennec-hub-angular-ui \
|
||||||
|
fennec-hub-commerce
|
||||||
|
do
|
||||||
|
echo "Pulling $repo..."
|
||||||
|
cd "$BASE_DIR/$repo"
|
||||||
|
git pull
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Git update completed."
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
echo "========================================"
|
||||||
|
echo "Building Docker images..."
|
||||||
|
echo "========================================"
|
||||||
|
|
||||||
|
cd "$BASE_DIR"
|
||||||
|
docker compose build
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy() {
|
||||||
|
echo "========================================"
|
||||||
|
echo "Starting backend and frontend..."
|
||||||
|
echo "========================================"
|
||||||
|
|
||||||
|
cd "$BASE_DIR"
|
||||||
|
docker compose up -d
|
||||||
|
}
|
||||||
|
|
||||||
|
logs() {
|
||||||
|
docker logs -f fennec-backend
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $(basename "$0") {update|build|deploy|logs|all}"
|
||||||
|
echo
|
||||||
|
echo "Commands:"
|
||||||
|
echo " update Pull latest changes from all Git repositories"
|
||||||
|
echo " build Build Docker images"
|
||||||
|
echo " deploy Start backend and frontend"
|
||||||
|
echo " logs Follow backend logs"
|
||||||
|
echo " all Update, build, and deploy"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
update)
|
||||||
|
update
|
||||||
|
;;
|
||||||
|
build)
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
deploy)
|
||||||
|
deploy
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
logs
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
update
|
||||||
|
build
|
||||||
|
deploy
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user