diff --git a/bkp/azdo-tickets-between-branches.sh b/bkp/azdo-tickets-between-branches.sh new file mode 100755 index 0000000..ca1aee9 --- /dev/null +++ b/bkp/azdo-tickets-between-branches.sh @@ -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 +# +# 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 " >&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/" + 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' diff --git a/bkp/docker-compose copy.yml b/bkp/docker-compose copy.yml new file mode 100644 index 0000000..421bb80 --- /dev/null +++ b/bkp/docker-compose copy.yml @@ -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 \ No newline at end of file diff --git a/bkp/docker-compose-latest.yml b/bkp/docker-compose-latest.yml new file mode 100644 index 0000000..1c28b66 --- /dev/null +++ b/bkp/docker-compose-latest.yml @@ -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 \ No newline at end of file diff --git a/bkp/docker-compose-noui.yml b/bkp/docker-compose-noui.yml new file mode 100644 index 0000000..498d2d6 --- /dev/null +++ b/bkp/docker-compose-noui.yml @@ -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 + diff --git a/bkp/docker-compose.yml b/bkp/docker-compose.yml new file mode 100644 index 0000000..bebf817 --- /dev/null +++ b/bkp/docker-compose.yml @@ -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 + diff --git a/bkp/docker-compose.yml.bkp b/bkp/docker-compose.yml.bkp new file mode 100644 index 0000000..ff767ad --- /dev/null +++ b/bkp/docker-compose.yml.bkp @@ -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 + diff --git a/bkp/fennec.sh b/bkp/fennec.sh new file mode 100644 index 0000000..1f93298 --- /dev/null +++ b/bkp/fennec.sh @@ -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