docker release

This commit is contained in:
2026-09-06 17:35:22 +12:00
parent ee51d3983a
commit 15a19cfb44
7 changed files with 472 additions and 0 deletions

View 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'

View 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

View 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

View 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
View 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

View 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
View 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