Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 8 additions & 49 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Build Affected

on:
workflow_call:
inputs:
base:
required: true
type: string

jobs:
build:
Expand Down Expand Up @@ -29,57 +33,12 @@ jobs:
run: npm ci

- name: Build Affected
run: npx nx affected:build --configuration=production --exclude=ark-cacher-node,conan-cacher --base=origin/development --parallel=2
run: npx nx affected:build --configuration=production --base=${{ inputs.base }} --parallel=2

# Iterate through the dist folder and for any folder in dist/apps that has the suffix "-nest",
# copy the root package.json to the /app/<project-name> folder.
#
# This is necessary because as of this version of Nx, it cannot reliably generate a package.json for NestJS applications.
# and the more common issue is missing required database drivers.
- name: Inject Package JSON
- name: Copy Files Needed For Image Build
run: |
shopt -s nullglob

# Check if dist/apps exists
if [ ! -d dist/apps ]; then
echo "dist/apps does not exist"
exit 0
fi

for d in dist/apps/*-nest; do
echo "Copying package.json to $d"
cp package.json "$d"
done

echo ""
echo "Listing dist/apps"
ls dist/apps/

shopt -u nullglob

# Static angular applications can have environment variables injected at container runtime using the
# tokenSubstitute.sh script. This script is copied to the dist/apps/<project-name>-angular folder.
#
- name: Inject Token Subsitution Script
run: |
shopt -s nullglob

# Check if dist/apps exists
if [ ! -d dist/apps ]; then
echo "dist/apps does not exist"
exit 0
fi

for d in dist/apps/*-angular; do
echo "Copying tokenSubstitute.sh to $d"
cp scripts/ci/tokenSubstitute.sh "$d"
done

echo ""
echo "Listing dist/apps"
ls dist/apps/

shopt -u nullglob
mkdir -p dist
cp -r package.json package-lock.json dist/

- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Lint Affected

on:
workflow_call:
inputs:
base:
required: true
type: string

jobs:
lint:
Expand Down Expand Up @@ -30,4 +34,4 @@ jobs:
run: npm ci

- name: Lint Affected
run: npx nx affected:lint --configuration=production --exclude=ark-cacher-node,conan-cacher --base=origin/development --parallel=2
run: npx nx affected:lint --configuration=production --base=${{ inputs.base }} --parallel=2
28 changes: 27 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,36 @@ on:
push:

jobs:
set-base:
name: Set Base Reference
runs-on: ubuntu-latest
outputs:
base: ${{ steps.set-base.outputs.base }}
steps:
- name: Set Base Reference
id: set-base
run: |
if [[ "${{ github.ref_name }}" == "development" || "${{ github.ref_name }}" == "master" ]]; then
echo "base=HEAD~1" >> $GITHUB_OUTPUT
else
echo "base=origin/development" >> $GITHUB_OUTPUT
fi

lint:
name: Lint
needs: set-base
uses: ./.github/workflows/lint.yml
with:
base: ${{ needs.set-base.outputs.base }}

build:
name: Build
needs: lint
needs: [lint, set-base]
uses: ./.github/workflows/build.yml
with:
base: ${{ needs.set-base.outputs.base }}

publish:
name: Publish
needs: [lint, build]
uses: ./.github/workflows/publish.yml
52 changes: 32 additions & 20 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,45 @@
name: Build and Publish Images

on:
pull_request:
types: [labeled]
workflow_call:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
list-publishable:
# Only run this job if pull request label is equal to "release"
# If this condition fails, build-and-publish will not run
if: ${{ github.event.label.name == 'release' }}
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
matrix: ${{ steps.set-matrix.outputs.matrix || '[]' }}
steps:
- name: 'Download artifacts'
uses: dawidd6/action-download-artifact@v2
uses: actions/download-artifact@v4
with:
workflow: main.yml
name: ${{ github.event.pull_request.head.sha }}
path: artifacts
name: ${{ github.sha }}
- name: 'Check for produced artifacts'
id: check-apps
run: |
if [ -d "./apps" ]; then
echo "✅ Apps directory found - proceeding with image build matrix generation"
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "⚠️ Apps directory not found - skipping image builds"
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: 'Set matrix'
id: set-matrix
if: steps.check-apps.outputs.exists == 'true'
# Run script to generate matrix by getting a list of all directories that have a dockerfile as json array in the /artifact directory
run: |
cd ./artifacts/apps
cd ./apps
JASON=$(find . -name "Dockerfile" -exec dirname {} \; | sed 's/^\.\///' | jq -R -s -c 'split("\n")[:-1]')
echo $JASON
echo "matrix=$JASON" >> $GITHUB_OUTPUT
build-and-push:
needs: list-publishable
runs-on: ubuntu-latest
if: ${{ needs.list-publishable.outputs.matrix != '[]' }}
permissions:
contents: read
packages: write
Expand All @@ -42,12 +48,9 @@ jobs:
image: ${{ fromJson(needs.list-publishable.outputs.matrix) }}
steps:
- name: 'Download artifacts'
uses: dawidd6/action-download-artifact@v2
uses: actions/download-artifact@v4
with:
workflow: main.yml
name: ${{ github.event.pull_request.head.sha }}
path: artifacts

name: ${{ github.sha }}
- name: Docker login
uses: docker/login-action@v3
with:
Expand All @@ -59,18 +62,27 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/Supreme-Gaming/${{ matrix.image }}
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.image }}
flavor: |
latest=true
tags: |
type=ref,event=branch
type=ref,event=pr
type=raw,value=stable,enable=${{ github.ref_name == 'development' }}
type=raw,value=stable,enable=${{ github.ref_name == 'master' }}
type=raw,value=${{ github.ref_name }},enable=${{ github.ref_name != 'development' && github.ref_name != 'master' }}
type=sha

- name: Copy required image build files
run: |
cp package.json package-lock.json apps/${{ matrix.image }}

- name: Build and push Docker images
uses: docker/build-push-action@v6
with:
context: ./artifacts/apps/${{ matrix.image }}
context: ./apps/${{ matrix.image }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
GIT_TAG=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
GIT_COMMIT=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
63 changes: 40 additions & 23 deletions apps/supremegaming-angular/src/.nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
listen 80 default_server;
listen [::]:80 default_server;
server_name _;

#access_log /var/log/nginx/host.access.log main;
root /usr/share/nginx/html;
index index.html index.htm;

location / {
root /usr/share/nginx/html;
index index.html index.htm;

# Route all requests to index.html for an SPA
try_files $uri $uri/ /index.html;
# 1) Long-cache immutable assets (hash-named)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
access_log off;
expires off;
add_header Cache-Control "public, max-age=31536000, immutable" always;
}

#error_page 404 /404.html;
# 2) Never cache the HTML shell and web app manifests
location = /index.html {
expires off;
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
add_header Pragma "no-cache" always;
}
location = /manifest.webmanifest {
expires off;
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
add_header Pragma "no-cache" always;
}
location = /ngsw.json {
expires off;
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
add_header Pragma "no-cache" always;
}

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
# 3) SPA routing: send unknown paths to index.html
location / {
try_files $uri $uri/ /index.html;
# No need to repeat headers here; the internal redirect to =/index.html
# ensures the HTML no-cache policy above is applied.
}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# Errors
error_page 500 502 503 504 /50x.html;
location = /50x.html { }

# Optional hardening:
# add_header Referrer-Policy "no-referrer-when-downgrade" always;
# add_header X-Content-Type-Options "nosniff" always;
# add_header X-Frame-Options "SAMEORIGIN" always;
}
9 changes: 3 additions & 6 deletions apps/supremegaming-angular/src/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
FROM nginx:1.23.2-alpine

RUN apk add --no-cache bash
FROM ghcr.io/tamugeoinnovation/nginx-base:latest

COPY . /usr/share/nginx/html
COPY .nginx/nginx.conf /etc/nginx/conf.d/default.conf

COPY --chmod=0755 tokenSubstitute.sh /usr/share/nginx/html/tokenSubstitute.sh

ENTRYPOINT ["/usr/share/nginx/html/tokenSubstitute.sh"]
# Only run token substitution during build without starting nginx
RUN /usr/local/bin/tokenSubstitute.sh
4 changes: 2 additions & 2 deletions apps/supremegaming-angular/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { HttpClientModule } from '@angular/common/http';

import * as WebFont from 'webfontloader';

import { EnvironmentModule } from '@supremegaming/common/ngx';
import { EnvironmentModule, metadata } from '@supremegaming/common/ngx';
import { UiSkeletonModule } from '@supremegaming/ui';

import { AppRoutingModule } from './app-routing.module';
Expand All @@ -27,7 +27,7 @@ WebFont.load({
AppRoutingModule,
UiSkeletonModule,
HttpClientModule,
EnvironmentModule.forRoot(environment),
EnvironmentModule.forRoot({ ...environment, metadata }),
HttpClientModule,
],
declarations: [AppComponent],
Expand Down
2 changes: 2 additions & 0 deletions libs/common/ngx/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export * from './lib/modules/pipes/pipes.module';
export * from './lib/modules/meta/meta.module';
export * from './lib/modules/meta/meta.service';
export * from './lib/modules/meta/components/metadata/metadata.component';

export * from './lib/constants/build-traceability.constants';
17 changes: 17 additions & 0 deletions libs/common/ngx/src/lib/constants/build-traceability.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const metadata = {
buildDate: '___BUILD_DATE___',
gitCommit: '___GIT_COMMIT___',
gitTag: '___GIT_TAG___',
containerName: '___CONTAINER_NAME___',
nodeName: '___NODE_NAME___',
environment: '___ENVIRONMENT_MODE___',
};

export interface ReleaseMetadata {
buildDate: string;
gitCommit: string;
gitTag: string;
containerName: string;
nodeName: string;
environment: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,22 @@ export const ENVIRONMENT = 'environment';
providedIn: 'root',
})
export class EnvironmentService {
constructor(@Inject(ENVIRONMENT) private env) {}
constructor(@Inject(ENVIRONMENT) private env) {
if (env) {
if (env.metadata) {
// eslint-disable-next-line no-restricted-syntax
console.info(`Environment module initialized.\n`);
// eslint-disable-next-line no-restricted-syntax
console.info(`\n
Build Date: ${env.metadata.buildDate}
Git Commit: ${env.metadata.gitCommit}
Git Tag: ${env.metadata.gitTag}
Container Name: ${env.metadata.containerName}
Node Name: ${env.metadata.nodeName}\n
`);
}
}
}

/**
* Returns an environment value lookup by token.
Expand Down
Loading