Attempting to add CI/CD automation
This commit is contained in:
parent
beb5368e28
commit
6e3153bee8
2 changed files with 239 additions and 2 deletions
237
.forgejo/workflows/stagging.yml
Normal file
237
.forgejo/workflows/stagging.yml
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
# +=========================================================================================================================+
|
||||
# | 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 Main Bridgeman Accessible website to QA/Stagging (private Kubernetes cluster)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- stagging
|
||||
# I'm leaving this here because I've tried to add and then had to remove this several times
|
||||
# In particular, the problem is conditions are OR'd NOT AND'd
|
||||
# This means controls via branch commit rules combined with this workflow achieve a better result than having this here
|
||||
#tags:
|
||||
# - 'v[0-9]+.[0-9]+.[0-9]+' # Matches any semantic versioning tag (e.g. v1.0.0, v2.1.3, etc.)
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write # Allows the workflow to push changes to the repository (e.g. for tagging)
|
||||
|
||||
jobs:
|
||||
# Run tests (particularly unit tests) on the codebase
|
||||
# This mostly relies on the `yarn test` command
|
||||
#test:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
#
|
||||
# - name: Set up Node.js version
|
||||
# uses: actions/setup-node@v3
|
||||
# with:
|
||||
# # Take from [Repo README](https://github.com/actions/setup-node#readme)
|
||||
# #
|
||||
# # > Version Spec of the version to use in SemVer notation.
|
||||
# # > It also admits such aliases as lts/*, latest, nightly and canary builds
|
||||
# # > Examples: 12.x, 10.15.1, >=10.15.0, lts/Hydrogen, 16-nightly, latest, node
|
||||
# node-version: '18.x'
|
||||
#
|
||||
# # Take from [Repo README](https://github.com/actions/setup-node#readme)
|
||||
# #
|
||||
# # > Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file,
|
||||
# # > and set up auth to read in from env.NODE_AUTH_TOKEN.
|
||||
# # > Default: ''
|
||||
# registry-url: 'https://npm.pkg.bridgemanaccessible.ca'
|
||||
#
|
||||
# # Take from [Repo README](https://github.com/actions/setup-node#readme)
|
||||
# #
|
||||
# # > Optional scope for authenticating against scoped registries.
|
||||
# # > Will fall back to the repository owner when using the GitHub Packages registry (https://npm.pkg.github.com/).
|
||||
# scope: '@BridgemanAccessible'
|
||||
#
|
||||
# - name: yarn install and test
|
||||
# env:
|
||||
# NODE_AUTH_TOKEN: ${{ secrets.PRIVATE_NPM_TOKEN }}
|
||||
# run: |
|
||||
# yarn install
|
||||
# yarn test
|
||||
|
||||
# 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: |
|
||||
echo 'Harbor Username: ${{ env.HARBOR_USERNAME }}'
|
||||
|
||||
# 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
|
||||
|
||||
# Because a build and deploy is desired, we want to check if a new tag already exists or if we need to create one as part of the workflow
|
||||
# This is commented out because the approach here makes sense but the logic doesn't fully because we already know the git tag and the version don't match
|
||||
#- name: Tag Check
|
||||
# id: tag_check
|
||||
# if: steps.version_check.outputs.build_and_deploy == 'true'
|
||||
# run: |
|
||||
# # Check if a matching image build already exists
|
||||
# MATCHING_IMAGE=$(docker image ls $(jq -r '.name' package.json) | grep ${{ env.LATEST_TAG }} || echo "Image not found")
|
||||
#
|
||||
# # If a matching image exists, set the `create_tag` output to true (so that a new tag is created)
|
||||
# if [[ "$MATCHING_IMAGE" == "Image not found" ]]; then
|
||||
# echo "No matching image found, No new tag required"
|
||||
# echo "create_tag=false" >> $GITHUB_OUTPUT
|
||||
# else
|
||||
# echo "Matching image found, new tag required"
|
||||
# echo "create_tag=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'
|
||||
#if: steps.version_check.outputs.build_and_deploy && steps.tag_check.outputs.create_tag == 'true'
|
||||
run: |
|
||||
# Increment the version's patch number (within the `package.json` file)
|
||||
#jq '.version |= (. | split(".") | [.[0], .[1], (.[2] | tonumber + 1 | tostring)] | join("."))' package.json > temp.json && mv temp.json package.json
|
||||
|
||||
# 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 "Forgjo Actions"
|
||||
git config user.email "actions@git.bridgemanaccessible.ca"
|
||||
|
||||
# Commit the version change to the `package.json` file
|
||||
#git add package.json
|
||||
#git commit -m "[Github Actions] Update version to $(jq -r '.version' package.json)"
|
||||
|
||||
# Push the changes to the repository
|
||||
#git push origin HEAD:stagging
|
||||
|
||||
# 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: |
|
||||
IMAGE_NAME=ba-website
|
||||
|
||||
echo "Repository Path: $GITHUB_WORKSPACE"
|
||||
echo "Name for Image: $IMAGE_NAME"
|
||||
|
||||
# Not necessarily needed but keeping track of the current directory (so that we can return to it is just a good practice)
|
||||
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="ba-website"
|
||||
DEPLOYMENT_NAME="website"
|
||||
CONTAINER_NAME="website"
|
||||
IMAGE_NAME="ba-website"
|
||||
|
||||
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"
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "ba-website",
|
||||
"version": "1.0.0",
|
||||
"description": "A simple Express app",
|
||||
"version": "1.0.16",
|
||||
"description": "The Bridgeman Accessible main website",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node dist/server.js",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue