Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: initial new build process #3246

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
2e63a40
chore: initial new build process
rafasdc May 6, 2024
fb1c3ad
chore: use node 20
rafasdc Sep 4, 2024
0974ff1
chore: update yarn.lock
rafasdc Sep 4, 2024
6e92680
chore: disable webpack
rafasdc Sep 4, 2024
9e3fed6
chore: remove sentry webpack plugin
rafasdc Sep 4, 2024
bc0f0cf
chore: sentry wizard setup, use next swc compiler
rafasdc Sep 5, 2024
596cfe5
chore: remove sentry transaction from file widget
rafasdc Sep 5, 2024
c431523
chore: testing small change for build
rafasdc Sep 5, 2024
1c8df96
chore: temp disable move cache
rafasdc Sep 6, 2024
2194bcc
chore: update cache-to
rafasdc Sep 6, 2024
1924179
chore: test small change
rafasdc Sep 6, 2024
3f88a5d
chore: attempt to use ref
rafasdc Sep 6, 2024
fde2017
chore: cache app and deps separately
rafasdc Sep 6, 2024
88e397a
chore: small change
rafasdc Sep 6, 2024
6c37912
chore: dockerfile new strategy
rafasdc Sep 6, 2024
fb27fb1
chore: app change
rafasdc Sep 6, 2024
5288dc0
test: debugging
rafasdc Sep 18, 2024
43fb252
chore: reset es2017, move babel to test
rafasdc Sep 18, 2024
867fe19
chore: temp deploy
rafasdc Sep 18, 2024
0e1f067
test: temp reduce setTimeout
rafasdc Sep 18, 2024
6098e46
test: transform ignore patterns with next
rafasdc Sep 19, 2024
e47faf6
test: attempt use of v8
rafasdc Sep 20, 2024
585e4c8
test: update snapshot
rafasdc Sep 20, 2024
9951a89
chore: rebase main
rafasdc Oct 18, 2024
9c30284
test: update resolve file upload
rafasdc Oct 18, 2024
a1cb2f3
test: update style for navigation side bar
rafasdc Oct 21, 2024
ea0a483
test: update file component dropzone finder
rafasdc Oct 21, 2024
c4cd333
test: update stepper style
rafasdc Oct 21, 2024
1acac3f
test: update cbc parent element logic, add await act
rafasdc Oct 21, 2024
d486c87
test: switch from spy on intakeId to mocked query
rafasdc Oct 21, 2024
22d847b
test: add missing properties, remove spy on template
rafasdc Oct 21, 2024
1c557a6
test: cleanup next/router mock
rafasdc Oct 21, 2024
0bfd8d6
test: add before each for next/router
rafasdc Oct 21, 2024
262d888
chore: base debug
rafasdc Oct 23, 2024
ac9c267
chore: new base build
rafasdc Oct 23, 2024
414eb9e
chore: change app home
rafasdc Oct 23, 2024
da303bd
chore: update sonar exclusions
rafasdc Oct 23, 2024
929d7ee
chore: add missing ,
rafasdc Oct 23, 2024
03454e4
chore: debug cache
rafasdc Oct 23, 2024
4585cd8
chore: cache sync path change
rafasdc Oct 23, 2024
e7077c7
chore: revert back to application
rafasdc Oct 23, 2024
37ed33d
chore: update upload directory
rafasdc Oct 23, 2024
ea205a4
chore: different uploads approach
rafasdc Oct 23, 2024
194acc9
chore: add missing variables for uploads
rafasdc Oct 23, 2024
2167b08
chore: attempt use gha cache
rafasdc Oct 23, 2024
0be70c0
test: e2e application intake stop chaining
rafasdc Oct 23, 2024
fca7dbc
test: update cypress, add retries
rafasdc Oct 24, 2024
9c1c245
fix: authorized path for gis
rafasdc Oct 24, 2024
bdeb4cb
chore: attempt re setup build workflow
rafasdc Oct 24, 2024
f8e460a
chore: add checkout
rafasdc Oct 24, 2024
f9691ec
test: attempt alternate waits
rafasdc Oct 24, 2024
50e276a
chore: attempt yarn cache
rafasdc Oct 24, 2024
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
53 changes: 35 additions & 18 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,12 @@ jobs:
packages: write
name: ${{ matrix.name }}
steps:
- name: Checkout repository
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
with:
install: true
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
Expand All @@ -57,43 +56,61 @@ jobs:
tags: |
type=sha,format=long,prefix=sha-
latest

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Cache Docker layers
uses: actions/cache@v4
# Cache node_modules based on package.json and yarn.lock
# - name: Cache dependencies (node_modules and patches)
# uses: actions/cache@v4
# with:
# path: /tmp/.buildx-cache
# key: ${{ runner.os }}-buildx-${{ matrix.name }}-deps-${{ hashFiles('app/package.json', 'app/yarn.lock', 'app/patches/*') }}
# restore-keys: |
# ${{ runner.os }}-buildx-${{ matrix.name }}-deps-
# # Cache app build separately based on app code
# - name: Cache app code build
# uses: actions/cache@v4
# with:
# path: /tmp/.buildx-cache-app
# key: ${{ runner.os }}-buildx-${{ matrix.name }}-app-${{ hashFiles('app/**/*') }}
# restore-keys: |
# ${{ runner.os }}-buildx-${{ matrix.name }}-app-
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT

- uses: actions/cache@v4
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ matrix.name }}-${{ github.sha }}
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-buildx-${{ matrix.name }}

${{ runner.os }}-yarn-
- name: Build and push Docker image
env:
GIT_HASH: ${{ env.GIT_HASH }}
SENTRY_AUTH_TOKEN: ${{ env.SENTRY_AUTH_TOKEN }}
uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
builder: ${{ steps.buildx.outputs.name }}
# builder: ${{ steps.buildx.outputs.name }}
push: true
file: ${{ matrix.dockerfile }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
SENTRY_AUTH_TOKEN=${{ env.SENTRY_AUTH_TOKEN }}
GIT_HASH=${{ env.GIT_HASH }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
cache-from: type=gha
cache-to: type=gha,mode=max
# Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
# - name: Move cache
# run: |
# rm -rf /tmp/.buildx-cache
# mv /tmp/.buildx-cache-new /tmp/.buildx-cache
4 changes: 2 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ jobs:
- run: ./.bin/sqitch-last-change-is-tag.sh db

deploy:
if: github.event.ref == 'refs/heads/main'
needs: [test-code, test-containers]
# if: github.event.ref == 'refs/heads/main'
needs: [build]
uses: ./.github/workflows/deploy.yaml
secrets:
OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }}
Expand Down
12 changes: 0 additions & 12 deletions app/.babelrc

This file was deleted.

1 change: 1 addition & 0 deletions app/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.js
!*.cy.js
!e2e.js
instrumentation.ts
3 changes: 3 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ yalc.lock
# Persisted queries
.persisted_operations
/schema/queryMap.json

# Sentry Config File
.env.sentry-build-plugin
161 changes: 96 additions & 65 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM registry.access.redhat.com/ubi9/s2i-base@sha256:ba798a9d1f392ed6c2315cbcc6e311722a5d979ae591b94a00a1dd0ab06f9fff
# Base stage to install global dependencies
FROM node:20-alpine AS base

ENV SUMMARY="An image for the CONN-CCBC-portal app" \
DESCRIPTION="This image contains the compiled CONN-CCBC-portal node app"
Expand All @@ -12,79 +13,109 @@
vendor="Province of British Columbia" \
maintainer="Romer, Meherzad CITZ:EX <[email protected]>"

ENV USER_ID=1001
ENV APP_HOME=/root
ENV HOME=/root
# Environment variables
ARG GIT_HASH
ENV GIT_HASH=${GIT_HASH}
ARG SENTRY_AUTH_TOKEN

Check warning on line 18 in app/Dockerfile

View workflow job for this annotation

GitHub Actions / build / app

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "SENTRY_AUTH_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENV USER_ID=1001
ENV APP_HOME=/application
ENV GIT_HASH=${GIT_HASH}
ENV SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN}

Check warning on line 22 in app/Dockerfile

View workflow job for this annotation

GitHub Actions / build / app

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "SENTRY_AUTH_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENV UPLOAD_DIR=${APP_HOME}/uploads

WORKDIR ${APP_HOME}

RUN INSTALL_PKGS="yarn-1.22.18-1" && \
yum -y update && \
curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo > /etc/yum.repos.d/yarn.repo && \
rpm --import https://dl.yarnpkg.com/rpm/pubkey.gpg && \
yum -y install --setopt=tsflags=nodocs $INSTALL_PKGS && \
rpm -V $INSTALL_PKGS && \
yum -y clean all --enablerepo='*' && \
rm -rf /var/cache

# Install asdf package manager
RUN git clone https://github.com/asdf-vm/asdf.git ${APP_HOME}/asdf --branch v0.8.1 && \
cd ${APP_HOME}/asdf && \
git checkout v0.8.1
ENV BASH_ENV="${APP_HOME}/asdf/asdf.sh"
# Because asdf is loaded via BASH_ENV, all commands using adsf need to be executed using /usr/bin/env bash -c
SHELL ["/usr/bin/env", "bash", "-c"]

# The app container only needs yarn and node; make sure they're installed
COPY .tool-versions ${APP_HOME}/.tool-versions
RUN sed -i -nr '/node|yarn/p' ${APP_HOME}/.tool-versions && \
cat ${APP_HOME}/.tool-versions | cut -f 1 -d ' ' | xargs -n 1 asdf plugin-add && \
asdf plugin-update --all && \
asdf install && \
asdf reshim && \
pushd ${APP_HOME}/.asdf/installs/nodejs/$(awk '/^nodejs/ { print $2 }' .tool-versions)/lib && \
npm i npm corepack && \
rm -f package.json package-lock.json && \
popd

ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 /usr/local/bin/dumb-init
RUN chmod +x /usr/local/bin/dumb-init
ENTRYPOINT ["dumb-init", "--", "/usr/bin/env", "bash", "-c"]

COPY app/ ${APP_HOME}/

# FIX CVE-2022-29244
RUN rm -rf /usr/local/bin/npm \
&& rm -rf /root/.npm
# Install system dependencies
RUN apk add --no-cache libc6-compat

# 1ST STAGE: INSTALL ALL DEPENDENCIES NEEDED FOR BUILD --

# Install both dev and prod dependencies during build
FROM base AS deps

# Copy only package.json yarn.lock and the patches for caching purposes
COPY app/patches patches
COPY app/package.json .
COPY app/yarn.lock .

# Install all dependencies (including dev) to ensure build tools are available
RUN yarn --frozen-lockfile

# -- END OF 1ST STAGE --

# -- 2ND STAGE: BUILD THE APP --

# Build the app
FROM base AS builder

# Copy node_modules from the deps stage
COPY --from=deps ${APP_HOME}/node_modules ./node_modules

# Copy the application source code
COPY app/ .

# Build the app (compile Relay, server, and Next.js)
ENV NODE_ENV=production
RUN yarn build:relay
RUN yarn build:server
RUN yarn build:next

# -- END OF 2ND STAGE --

# -- 3RD STAGE: PRODUCTION DEPENDENCIES --

# Separate stage for production dependencies to leverage Docker caching
FROM base AS prod-deps

# Copy only package.json yarn.lock and the patches for caching purposes
COPY app/patches patches
COPY app/package.json .
COPY app/yarn.lock .

# Install only production dependencies so this layer can be cached separately
RUN yarn install --frozen-lockfile --production=true --prefer-offline

# -- END OF 3RD STAGE --

# -- FINAL STAGE --
# Production image to run the application
FROM node:20-alpine AS runner

# Env variables for the final image
ENV APP_HOME=/application
ENV UPLOAD_DIR=${APP_HOME}/uploads
ENV USER_ID=1001
ENV NODE_ENV=production
ENV ENABLE_ANALYTICS=true

RUN PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 CYPRESS_INSTALL_BINARY=0 \
yarn install --frozen-lockfile --production=false && \
yarn build:relay && \
yarn build:server && \
yarn build:next && \
yarn install --frozen-lockfile --production=true && \
yarn cache clean && \
# Make everything in the home group-writable to support OpenShift's restricted SCC
# Needs to be done as root to chown
# same layer as yarn install to keep re-chowned files from using up several hundred MBs more space
chown -R ${USER_ID}:0 ${APP_HOME} && \
chmod -R g+rwX ${APP_HOME}

# Create a directory for uploads
RUN mkdir -p ${UPLOAD_DIR} && \
chown -R ${USER_ID}:0 ${UPLOAD_DIR} && \
chmod -R g+rw ${UPLOAD_DIR}

EXPOSE 3000 9000
USER ${USER_ID}
WORKDIR ${APP_HOME}

CMD ["yarn start"]
# Create a non-root user for OCP
RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001

COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/public ./public
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/.next ./.next
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/.persisted_operations ./.persisted_operations
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/config ./config
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/schema ./schema
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/*.json5 .
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/*.ts .
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/*.js .
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/*.properties .
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/*.json .
COPY --from=builder --chown=${USER_ID}:0 ${APP_HOME}/dist ./dist

# Copy production dependencies
COPY --from=prod-deps --chown=${USER_ID}:0 ${APP_HOME}/node_modules ./node_modules

# Make sure uploads directory has proper permission
RUN mkdir -p ${UPLOAD_DIR}
RUN chown -PR ${USER_ID}:0 ${UPLOAD_DIR}
RUN chmod -R g+rw ${UPLOAD_DIR}

# Run as the non-root user
USER ${USER_ID}

# Expose ports
EXPOSE 3000 9000

# Command to run the application
CMD ["node", "--unhandled-rejections=strict", "--enable-network-family-autoselection", "dist/server.js"]
13 changes: 0 additions & 13 deletions app/babel.config.json

This file was deleted.

2 changes: 1 addition & 1 deletion app/backend/lib/express-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const isDeployedToOpenShift =
export const commonFormidableConfig: formidable.Options = {
maxFileSize: 8000000,
keepExtensions: false,
uploadDir: isDeployedToOpenShift ? '/root/uploads' : undefined,
uploadDir: isDeployedToOpenShift ? '/application/uploads' : undefined,
allowEmptyFiles: true,
minFileSize: 0,
};
19 changes: 0 additions & 19 deletions app/backend/lib/graphql/resolveFileUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@ if (!isDeployedToOpenShift) {
}

export const saveRemoteFile = async (stream) => {
const transaction = Sentry.startTransaction({ name: 'ccbc.function' });
const span = transaction.startChild({
op: 'resolve-file-upload',
description: 'resolveFileUpload saveRemoteFile function',
});
span.setData('start-of-funciton-call', new Date().toISOString());

try {
console.time('saveRemoteFile');

Expand Down Expand Up @@ -79,29 +72,17 @@ export const saveRemoteFile = async (stream) => {
const uploadProgressInMB =
Math.round((progress.loaded / 1000000) * 10) / 10;
console.log(`Uploaded ${uploadProgressInMB}MB`);
transaction.setMeasurement('memoryUsed', uploadProgressInMB, 'megabtye');
});
span.setData('upload-start', new Date().toISOString());
const data = await parallelUploads3.done();
span.setData('upload-finish', new Date().toISOString());

const key = (data as CompleteMultipartUploadCommandOutput)?.Key;

if (!key) {
throw new Error('Data does not contain a key');
}

span.setStatus('ok');
span.finish();
transaction.finish();

return key;
} catch (err) {
span.setData('error-obj', err);
span.setStatus('unknown_error');
span.finish();
transaction.finish();

console.log('Error', err);
throw new Error(err);
} finally {
Expand Down
1 change: 1 addition & 0 deletions app/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const happoTask = require('happo-cypress/task');
export default defineConfig({
video: false,
pageLoadTimeout: 100000,
retries: 2,
fixturesFolder: '../db/data',
e2e: {
setupNodeEvents(on, config) {
Expand Down
Loading
Loading