Automation + package updates etc...

This commit is contained in:
Alan Bridgeman 2025-06-19 02:20:17 -05:00
parent dd12f8b123
commit 42b8a6fd0e
3 changed files with 178 additions and 12 deletions

View file

@ -0,0 +1,158 @@
# +=========================================================================================================================+
# | QA/Stagging CI/CD workflow |
# | |
# | Our QA/Stagging environment is hosted on servers in our office using a combination of: |
# | - Kubernetes (10 Ubuntu 24.04 VM nodes, hosted within a Proxmox VE cluster of 2 servers, a Dell R730xd and a Dell R730) |
# | - Nginx Proxy Manager as a reverse proxy |
# | - Pi-hole for DHCP |
# | - Bind for custom DNS |
# | On a cluster wide level: |
# | - Rook/Ceph |
# | - MetalLb |
# | - Nginx Ingress Controller |
# | - PosgreSQL Operator (CloudNativePG) |
# | - Custom PostgreSQL Database Operation (https://github.com/AlanBridgeman/postgres-controller) |
# | - MongoDB Community Operator |
# | On a namespace level: |
# | - Redis |
# | - Hasshicorp Vault |
# | - Mongo containers |
# | |
# | It's worth noting we largely use Helm to deploy resources into the cluster. |
# +=========================================================================================================================+
name: Build and deploy Harbor Helm Index to QA/Stagging (private Kubernetes cluster)
on:
push:
branches:
- stagging
workflow_dispatch:
permissions:
contents: write # Allows the workflow to push changes to the repository (e.g. for tagging)
jobs:
# Builds the codebase (builds the image)
build:
runs-on: self-hosted
outputs:
build_and_deploy: ${{ steps.version_check.outputs.build_and_deploy }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare Environment Variables
run: |
echo "Harbor Username: ${{ secrets.HARBOR_USERNAME }}"
echo "HARBOR_USERNAME=${{ secrets.HARBOR_USERNAME }}" >> $GITHUB_ENV
echo "Harbor Password: ${{ secrets.HARBOR_PASSWORD }}"
echo "HARBOR_PASSWORD=${{ secrets.HARBOR_PASSWORD }}" >> $GITHUB_ENV
# Check if this is a "significant" commit that should trigger a build and deploy
# This is done by checking if the latest git tag matches the version in the `package.json` file
- name: Version Check
id: version_check
run: |
# Get the latest version from the `package.json` file
# This should be updated if a new build and deploy is desired
LATEST_VERSION=$(jq -r '.version' package.json)
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
# Get the latest Git tag from the repository
LATEST_TAG=$(git describe --tags --abbrev=0)
echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV
# If the git tag and the version ARE the same, this is a commit that SHOULD NOT trigger a build and deploy
# Inversely, if the git tag and the version are NOT the same, this is a commit that SHOULD trigger a build and deploy
if [[ "$LATEST_TAG" == "v$LATEST_VERSION" ]]; then
echo "Latest tag matches the version in package.json, SHOULD NOT build and deploy"
echo "build_and_deploy=false" >> $GITHUB_OUTPUT
else
echo "Latest tag does not match the version in package.json, SHOULD build and deploy"
echo "build_and_deploy=true" >> $GITHUB_OUTPUT
fi
# Conditional step to create a new Git tag
# This is required because when we go to build and deploy the image we rely on the latest git tag
# We do it this way so that ONLY situations where the git tag and the last built image are mal-aligned do we create a new tag
- name: Add Git Tag (if needed)
if: steps.version_check.outputs.build_and_deploy == 'true'
run: |
# Update remote URL to use the GITHUB_TOKEN for authentication
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@git.bridgemanaccessible.ca/${{ github.repository }}.git
# Setup git user details for committing the version change and tag
git config user.name "Forgejo Actions"
git config user.email "actions@git.bridgemanaccessible.ca"
# Create a new tag with the updated version number
git tag -a "v${{ env.LATEST_VERSION }}" -m "Version ${{ env.LATEST_VERSION }}"
# Push the new tag to the repository
git push --tags
# Run the build script found on self-hosted runner
- name: Run Build Image Script
if: steps.version_check.outputs.build_and_deploy == 'true'
run: |
CURR_DIR="$PWD"
# Change into the repository directory
cd "$GITHUB_WORKSPACE"
IMAGE_TAG=$(git describe --tags --abbrev=0) # Use the most recent tag as the image tag
IMAGE_FULL_NAME="containers.bridgemanaccessible.ca/k8s/${IMAGE_NAME}:${IMAGE_TAG}"
echo "🔹 Building and pushing image..."
docker build -t ${IMAGE_FULL_NAME} .
docker login -u $HARBOR_USERNAME -p $HARBOR_PASSWORD containers.bridgemanaccessible.ca
docker push ${IMAGE_FULL_NAME}
cd "$CURR_DIR"
echo "✅ Build successful!"
deploy:
runs-on: self-hosted
needs: build
if: needs.build.outputs.build_and_deploy == 'true'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get the latest tag
id: get_latest_tag
run: |
LATEST_TAG=$(git describe --tags --abbrev=0)
echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV
echo "IMAGE_VERSION=${LATEST_TAG#v}" >> $GITHUB_ENV
#- name: Prepare Environment Variables
# run: |
# echo "HARBOR_USERNAME=${{ secrets.HARBOR_USERNAME }}" >> $GITHUB_ENV
# echo "HARBOR_PASSWORD=${{ secrets.HARBOR_PASSWORD }}" >> $GITHUB_ENV
- name: Run Deploy Kubernetes Script
run: |
IMAGE_VERSION="${{ env.IMAGE_VERSION }}"
NAMESPACE="harbor-helm-index"
DEPLOYMENT_NAME="helm-index"
CONTAINER_NAME="helm-index"
IMAGE_NAME="harbor-helm-index"
echo "Image Version: $IMAGE_VERSION"
echo "Namespace: $NAMESPACE"
echo "Deployment Name: $DEPLOYMENT_NAME"
echo "Container Name: $CONTAINER_NAME"
echo "Image Name: $IMAGE_NAME"
update-k8s-deployment-image \
--image-version $IMAGE_VERSION \
--namespace $NAMESPACE \
--deployment-name $DEPLOYMENT_NAME \
--container-name $CONTAINER_NAME \
--image-name "containers.bridgemanaccessible.ca/k8s/$IMAGE_NAME"

View file

@ -29,6 +29,5 @@
"pg": "^8.13.3", "pg": "^8.13.3",
"typeorm": "^0.3.20", "typeorm": "^0.3.20",
"uuid": "^11.0.5" "uuid": "^11.0.5"
}, }
"packageManager": "yarn@1.22.22"
} }

View file

@ -1,5 +1,4 @@
import path from 'path'; import path from 'path';
import { Application } from 'express';
import { App, Initializer, globalTemplateValues } from '@BridgemanAccessible/ba-web-framework'; import { App, Initializer, globalTemplateValues } from '@BridgemanAccessible/ba-web-framework';
import { createConn } from './utils/db'; import { createConn } from './utils/db';
@ -20,20 +19,30 @@ async function createInitialDatabaseConnection() {
await createConn('postgres', connOptions); await createConn('postgres', connOptions);
} }
async function onStart(app: Application) { async function onStart(app: App) {
// Create the initial database connection // Create the initial database connection
createInitialDatabaseConnection(); createInitialDatabaseConnection();
} }
async function main() { async function main() {
await new App().run(new Initializer({ await new App().run(
controllersPath: path.join(__dirname, 'routes'), new Initializer(
staticFilesPath: path.join(__dirname, 'static'), {
view: { controllersPath: path.join(__dirname, 'routes'),
engine: 'ejs', staticFilesPath: path.join(__dirname, 'static'),
filesPath: path.join(__dirname, 'pages') view: {
} engine: 'ejs',
}, globalTemplateValues({ company: process.env.COMPANY, titleSuffix: process.env.WEBSITE_TITLE_SUFFIX, hostname: process.env.HOSTNAME })), onStart); filesPath: path.join(__dirname, 'pages')
}
},
globalTemplateValues({
company: process.env.COMPANY,
titleSuffix: process.env.WEBSITE_TITLE_SUFFIX,
hostname: process.env.HOSTNAME
})
),
onStart
);
} }
main() main()