From a57052317b514c84d8be13e6a559264da82026d8 Mon Sep 17 00:00:00 2001 From: Eng-Omar-Hussein Date: Mon, 30 Mar 2026 20:16:20 +0200 Subject: [PATCH 01/13] feat: add Docker Compose setup for local development --- .env | 11 ++ Jenkinsfile | 266 +++++++++++++++++++++++++-------------------- README.md | 13 +++ docker-compose.yml | 38 +++++++ 4 files changed, 209 insertions(+), 119 deletions(-) create mode 100644 .env create mode 100644 docker-compose.yml diff --git a/.env b/.env new file mode 100644 index 00000000..965bc5a2 --- /dev/null +++ b/.env @@ -0,0 +1,11 @@ +WORKSPACE_ = "/home/jenkins/agent/workspace" +NODE_ENV = 'production' +TZ = "UTC" +# // Amount of available vCPUs, to avoid OOM - https://www.gatsbyjs.com/docs/how-to/performance/resolving-out-of-memory-issues/#try-reducing-the-number-of-cores +# // https://github.com/jenkins-infra/jenkins-infra/tree/production/hieradata/clients/controller.ci.jenkins.io.yaml#L327 +GATSBY_CPU_COUNT = "4" +# // Added the below to fix permissions issue with the cache +GATSBY_CACHE_DIR = "${WORKSPACE_}/.gatsby-cache" +GATSBY_INTERNAL_CACHE_DIR = "${WORKSPACE_}/.cache" +GATSBY_TELEMETRY_DISABLED = "1" +NODE_OPTIONS = "--no-warnings" diff --git a/Jenkinsfile b/Jenkinsfile index 7f36c72a..e1e50b09 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,132 +1,160 @@ pipeline { - options { - timeout(time: 60, unit: 'MINUTES') - ansiColor('xterm') - disableConcurrentBuilds(abortPrevious: true) - buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '5', numToKeepStr: '5') - } + options { + timeout(time: 60, unit: 'MINUTES') + ansiColor('xterm') + disableConcurrentBuilds(abortPrevious: true) + buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '5', numToKeepStr: '5') + } - agent { - label 'linux-arm64-docker || arm64linux' - } + agent { + label 'linux-arm64-docker || arm64linux' + } - environment { - NODE_ENV = 'production' - TZ = "UTC" - // Amount of available vCPUs, to avoid OOM - https://www.gatsbyjs.com/docs/how-to/performance/resolving-out-of-memory-issues/#try-reducing-the-number-of-cores - // https://github.com/jenkins-infra/jenkins-infra/tree/production/hieradata/clients/controller.ci.jenkins.io.yaml#L327 - GATSBY_CPU_COUNT = "4" - // Added the below to fix permissions issue with the cache - GATSBY_CACHE_DIR = "${env.WORKSPACE}/.gatsby-cache" - GATSBY_INTERNAL_CACHE_DIR = "${env.WORKSPACE}/.cache" - GATSBY_TELEMETRY_DISABLED = "1" - NODE_OPTIONS = "--no-warnings" - } + stages { + stage('load env file') { + steps { + // Load environment variables from .env file. + sh ''' + set -a + source ./.env + set +a + ''' + } + } + + stage('Parallel Stage') { + parallel { + stage('Branch A') { + stages { + stage('Check for typos') { + steps { + sh ''' + curl - qsL https: //github.com/crate-ci/typos/releases/download/v1.33.1/typos-v1.33.1-x86_64-unknown-linux-musl.tar.gz | tar xvzf - ./typos + . / typos--format sarif > typos.sarif || true + ''' + } + post { + always { + recordIssues(tools: [sarif(id: 'typos', name: 'Typos', pattern: 'typos.sarif')]) + } + } + } - stages { - stage('Check for typos') { - steps { - sh ''' - curl -qsL https://github.com/crate-ci/typos/releases/download/v1.33.1/typos-v1.33.1-x86_64-unknown-linux-musl.tar.gz | tar xvzf - ./typos - ./typos --format sarif > typos.sarif || true - ''' - } - post { - always { - recordIssues(tools: [sarif(id: 'typos', name: 'Typos', pattern: 'typos.sarif')]) - } - } - } + stage('Install Dependencies') { + environment { + NODE_ENV = 'development' + } + steps { + sh 'asdf install' + sh 'npm install' + } + } - stage('Install Dependencies') { - environment { - NODE_ENV = 'development' - } - steps { - sh 'asdf install' - sh 'npm install' - } - } + stage('Lint and Test') { + environment { + NODE_ENV = "development" + } + steps { + sh 'npm run lint && npx eslint --format checkstyle > eslint.xml' + } + post { + always { + recordIssues(tools: [checkStyle(pattern: 'eslint.xml')]) + } + } + } - stage('Lint and Test') { - environment { - NODE_ENV = "development" - } - steps { - sh 'npm run lint && npx eslint --format checkstyle > eslint.xml' + stage('Build PR') { + when { + changeRequest() + } + environment { + NODE_ENV = 'development' + } + steps { + sh 'npm run build' + } + } + } + } + stage('Branch B') { + agent { + label 'linux-arm64-docker' + } + steps { + echo 'Test Docker Compose' + sh 'docker compose up' + sh 'docker compose run --rm stories_webapp env' + sh 'docker compose down' + } + post { + always { + sh 'docker compose down || true' + } + } + } + } } - post { - always { - recordIssues(tools: [checkStyle(pattern: 'eslint.xml')]) - } - } - } - stage('Build PR') { - when { changeRequest() } - environment { - NODE_ENV = 'development' - } - steps { - sh 'npm run build' + stage('Deploy PR to preview site') { + when { + allOf { + changeRequest target: 'main' + // Only deploy to production from infra.ci.jenkins.io + expression { + infra.isInfra() + } + } + } + environment { + NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') + } + steps { + sh 'netlify-deploy --draft=true --siteName "jenkins-is-the-way" --title "Preview deploy for ${CHANGE_ID}" --alias "deploy-preview-${CHANGE_ID}" -d ./public' + } + post { + success { + recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'success', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") + } + failure { + recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'failure', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") + } + } } - } - stage('Deploy PR to preview site') { - when { - allOf{ - changeRequest target: 'main' - // Only deploy to production from infra.ci.jenkins.io - expression { infra.isInfra() } - } - } - environment { - NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') - } - steps { - sh 'netlify-deploy --draft=true --siteName "jenkins-is-the-way" --title "Preview deploy for ${CHANGE_ID}" --alias "deploy-preview-${CHANGE_ID}" -d ./public' + stage('Build Production') { + when { + branch "main" + } + steps { + sh 'npm run build' + } } - post { - success { - recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'success', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") - } - failure { - recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'failure', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") - } - } - } - - stage('Build Production') { - when { - branch "main" - } - steps { - sh 'npm run build' - } - } - stage('Deploy Production') { - when { - allOf { - branch "main" - // Only deploy to production from infra.ci.jenkins.io - expression { infra.isInfra() } - } - } - environment { - NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') - } - steps { - sh 'netlify-deploy --draft=false --siteName "jenkins-is-the-way" --title "Deploy" -d ./public' - } - post { - success { - recordDeployment('jenkins-infra', 'stories', env.GIT_COMMIT, 'success', 'https://jenkins-is-the-way.netlify.app', [environment: 'production']) - } - failure { - recordDeployment('jenkins-infra', 'stories', env.GIT_COMMIT, 'failure', 'https://jenkins-is-the-way.netlify.app', [environment: 'production']) - } - } - } - } + stage('Deploy Production') { + when { + allOf { + branch "main" + // Only deploy to production from infra.ci.jenkins.io + expression { + infra.isInfra() + } + } + } + environment { + NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') + } + steps { + sh 'netlify-deploy --draft=false --siteName "jenkins-is-the-way" --title "Deploy" -d ./public' + } + post { + success { + recordDeployment('jenkins-infra', 'stories', env.GIT_COMMIT, 'success', 'https://jenkins-is-the-way.netlify.app', [environment: 'production']) + } + failure { + recordDeployment('jenkins-infra', 'stories', env.GIT_COMMIT, 'failure', 'https://jenkins-is-the-way.netlify.app', [environment: 'production']) + } + } + } + } } diff --git a/README.md b/README.md index 04eb4e49..17b41f98 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,19 @@ npm run develop Open [http://localhost:8000](http://localhost:8000) on your browser to see the result +## Alternative Development Setup: Docker Compose + +You can also use Docker Compose for local development. + +### How to Use + +1. Ensure you have [Docker](https://www.docker.com/products/docker-desktop/) and [Docker Compose](https://docs.docker.com/compose/) installed. +2. In the project **root**, run: + ```bash + docker compose up + ``` +3. Open [http://localhost:8000](http://localhost:8000) in your browser. + ## Code Quality Tools ### Formatting diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..69011942 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,38 @@ +services: + stories_webapp: + # TODO: track version with updatecli - ref. https://github.com/jenkins-infra/jenkins-infra/blob/efe90908529525bb3c9e61c2eb920ada3b968f1a/updatecli/updatecli.d/jenkinscontroller-tools-maven.yaml#L17-L22 + image: jenkinsciinfra/jenkins-agent-ubuntu-22.04:2.91.1 + + ports: + - "8000:8000" + + # Load environment variables + env_file: + - .env + # Add docker-compose-specific env vars + environment: + CHOKIDAR_USEPOLLING: "true" + PATH: /home/jenkins/.asdf/shims:/home/jenkins/.asdf/bin:$PATH + NODE_ENV: development + + volumes: + - .:${WORKSPACE_}/stories + + working_dir: "${WORKSPACE_}/stories" + + user: jenkins + + entrypoint: [] + command: bash -c "asdf install && asdf current && npm -v && node -v && npm install && npm run dev" + + networks: + - stories_network + +networks: + stories_network: + driver: bridge + +volumes: + stories_node_modules: + stories_cache: + stories_internal_cache: From 93e051bfe9ba280c6df50b880f797f6609aeb919 Mon Sep 17 00:00:00 2001 From: Omar Hussein <117474007+Eng-Omar-Hussein@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:36:41 +0200 Subject: [PATCH 02/13] Modify command for stories_webapp service Updated the command in the stories_webapp service to use 'npm run develop'. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 69011942..13dc0e81 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,7 @@ services: user: jenkins entrypoint: [] - command: bash -c "asdf install && asdf current && npm -v && node -v && npm install && npm run dev" + command: bash -c "asdf install && asdf current && npm install && npm run develop" networks: - stories_network From e453497e105629586924479f45ab07eaa82052a4 Mon Sep 17 00:00:00 2001 From: Omar Hussein <117474007+Eng-Omar-Hussein@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:33:18 +0200 Subject: [PATCH 03/13] Refactor docker-compose.yml structure --- docker-compose.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 13dc0e81..a73f5500 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,8 +31,3 @@ services: networks: stories_network: driver: bridge - -volumes: - stories_node_modules: - stories_cache: - stories_internal_cache: From 8725cd2342d03dac7981a8996a18b31d7d39a749 Mon Sep 17 00:00:00 2001 From: Omar Hussein <117474007+Eng-Omar-Hussein@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:42:12 +0200 Subject: [PATCH 04/13] Modify docker-compose.yml for workspace variable usage Updated the volume and working directory paths to use the WORKSPACE_ variable. --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a73f5500..1c4ff867 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,9 +16,9 @@ services: NODE_ENV: development volumes: - - .:${WORKSPACE_}/stories + - .:${WORKSPACE_} - working_dir: "${WORKSPACE_}/stories" + working_dir: ${WORKSPACE_} user: jenkins From 9661f36f6aece2406f9f7c922e2e1d0e0caff2f9 Mon Sep 17 00:00:00 2001 From: Eng-Omar-Hussein Date: Sat, 4 Apr 2026 15:46:37 +0200 Subject: [PATCH 05/13] refactor: streamline Jenkinsfile stages and improve deployment logic --- Jenkinsfile | 291 +++++++++++++++++++++++++--------------------------- 1 file changed, 141 insertions(+), 150 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e1e50b09..961a8908 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,160 +1,151 @@ pipeline { - options { - timeout(time: 60, unit: 'MINUTES') - ansiColor('xterm') - disableConcurrentBuilds(abortPrevious: true) - buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '5', numToKeepStr: '5') - } - - agent { - label 'linux-arm64-docker || arm64linux' - } - - stages { - stage('load env file') { - steps { - // Load environment variables from .env file. - sh ''' - set -a - source ./.env - set +a - ''' - } + options { + timeout(time: 60, unit: 'MINUTES') + ansiColor('xterm') + disableConcurrentBuilds(abortPrevious: true) + buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '5', numToKeepStr: '5') + } + agent { + label 'linux-arm64-docker || arm64linux' + } + stages { + stage('load env file') { + steps { + // Load environment variables from .env file. + sh ''' + set -a + source ./.env + set +a + ''' } - - stage('Parallel Stage') { - parallel { - stage('Branch A') { - stages { - stage('Check for typos') { - steps { - sh ''' - curl - qsL https: //github.com/crate-ci/typos/releases/download/v1.33.1/typos-v1.33.1-x86_64-unknown-linux-musl.tar.gz | tar xvzf - ./typos - . / typos--format sarif > typos.sarif || true - ''' - } - post { - always { - recordIssues(tools: [sarif(id: 'typos', name: 'Typos', pattern: 'typos.sarif')]) - } - } - } - - stage('Install Dependencies') { - environment { - NODE_ENV = 'development' - } - steps { - sh 'asdf install' - sh 'npm install' - } - } - - stage('Lint and Test') { - environment { - NODE_ENV = "development" - } - steps { - sh 'npm run lint && npx eslint --format checkstyle > eslint.xml' - } - post { - always { - recordIssues(tools: [checkStyle(pattern: 'eslint.xml')]) - } - } - } - - stage('Build PR') { - when { - changeRequest() - } - environment { - NODE_ENV = 'development' - } - steps { - sh 'npm run build' - } - } - } + } + stage('Parallel Stage') { + parallel { + stage('Branch A') { + stages { + stage('Check for typos') { + steps { + sh ''' + curl - qsL https: //github.com/crate-ci/typos/releases/download/v1.33.1/typos-v1.33.1-x86_64-unknown-linux-musl.tar.gz | tar xvzf - ./typos + . / typos--format sarif > typos.sarif || true + ''' + } + post { + always { + recordIssues(tools: [sarif(id: 'typos', name: 'Typos', pattern: 'typos.sarif')]) + } + } } - stage('Branch B') { - agent { - label 'linux-arm64-docker' - } - steps { - echo 'Test Docker Compose' - sh 'docker compose up' - sh 'docker compose run --rm stories_webapp env' - sh 'docker compose down' - } - post { - always { - sh 'docker compose down || true' - } - } + stage('Install Dependencies') { + environment { + NODE_ENV = 'development' + } + steps { + sh 'asdf install' + sh 'npm install' + } } - } - } - - stage('Deploy PR to preview site') { - when { - allOf { - changeRequest target: 'main' - // Only deploy to production from infra.ci.jenkins.io - expression { - infra.isInfra() - } + stage('Lint and Test') { + environment { + NODE_ENV = "development" + } + steps { + sh 'npm run lint && npx eslint --format checkstyle > eslint.xml' + } + post { + always { + recordIssues(tools: [checkStyle(pattern: 'eslint.xml')]) + } + } } - } - environment { - NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') - } - steps { - sh 'netlify-deploy --draft=true --siteName "jenkins-is-the-way" --title "Preview deploy for ${CHANGE_ID}" --alias "deploy-preview-${CHANGE_ID}" -d ./public' - } - post { - success { - recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'success', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") + stage('Build PR') { + when { + changeRequest() + } + environment { + NODE_ENV = 'development' + } + steps { + sh 'npm run build' + } } - failure { - recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'failure', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") + } + } + stage('Branch B') { + agent { + label 'linux-arm64-docker || arm64linux' + } + steps { + echo 'Test Docker Compose' + sh 'docker compose up --detach --wait' + sh 'docker compose run --rm stories_webapp env' + sh 'docker compose down' + } + post { + always { + sh 'docker compose down || true' } - } + } + } } - - stage('Build Production') { - when { - branch "main" - } - steps { - sh 'npm run build' - } + } + stage('Deploy PR to preview site') { + when { + allOf { + changeRequest target: 'main' + // Only deploy to production from infra.ci.jenkins.io + expression { + infra.isInfra() + } + } } - - stage('Deploy Production') { - when { - allOf { - branch "main" - // Only deploy to production from infra.ci.jenkins.io - expression { - infra.isInfra() - } - } - } - environment { - NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') - } - steps { - sh 'netlify-deploy --draft=false --siteName "jenkins-is-the-way" --title "Deploy" -d ./public' - } - post { - success { - recordDeployment('jenkins-infra', 'stories', env.GIT_COMMIT, 'success', 'https://jenkins-is-the-way.netlify.app', [environment: 'production']) - } - failure { - recordDeployment('jenkins-infra', 'stories', env.GIT_COMMIT, 'failure', 'https://jenkins-is-the-way.netlify.app', [environment: 'production']) - } - } + environment { + NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') + } + steps { + sh 'netlify-deploy --draft=true --siteName "jenkins-is-the-way" --title "Preview deploy for ${CHANGE_ID}" --alias "deploy-preview-${CHANGE_ID}" -d ./public' + } + post { + success { + recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'success', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") + } + failure { + recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'failure', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") + } + } + } + stage('Build Production') { + when { + branch "main" + } + steps { + sh 'npm run build' + } + } + stage('Deploy Production') { + when { + allOf { + branch "main" + // Only deploy to production from infra.ci.jenkins.io + expression { + infra.isInfra() + } + } + } + environment { + NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') + } + steps { + sh 'netlify-deploy --draft=false --siteName "jenkins-is-the-way" --title "Deploy" -d ./public' + } + post { + success { + recordDeployment('jenkins-infra', 'stories', env.GIT_COMMIT, 'success', 'https://jenkins-is-the-way.netlify.app', [environment: 'production']) + } + failure { + recordDeployment('jenkins-infra', 'stories', env.GIT_COMMIT, 'failure', 'https://jenkins-is-the-way.netlify.app', [environment: 'production']) + } } - } -} + } + } +} \ No newline at end of file From 39b0ee90cea58c6521a50980360f58328bb9ee5c Mon Sep 17 00:00:00 2001 From: Omar Hussein <117474007+Eng-Omar-Hussein@users.noreply.github.com> Date: Sat, 4 Apr 2026 16:54:54 +0200 Subject: [PATCH 06/13] Refactor Jenkinsfile --- Jenkinsfile | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 961a8908..ecdb2836 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,20 +5,23 @@ pipeline { disableConcurrentBuilds(abortPrevious: true) buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '5', numToKeepStr: '5') } + agent { label 'linux-arm64-docker || arm64linux' } + stages { stage('load env file') { steps { // Load environment variables from .env file. sh ''' - set -a - source ./.env - set +a - ''' + set -a + source ./.env + set +a + ''' } } + stage('Parallel Stage') { parallel { stage('Branch A') { @@ -26,8 +29,8 @@ pipeline { stage('Check for typos') { steps { sh ''' - curl - qsL https: //github.com/crate-ci/typos/releases/download/v1.33.1/typos-v1.33.1-x86_64-unknown-linux-musl.tar.gz | tar xvzf - ./typos - . / typos--format sarif > typos.sarif || true + curl - qsL https: //github.com/crate-ci/typos/releases/download/v1.33.1/typos-v1.33.1-x86_64-unknown-linux-musl.tar.gz | tar xvzf - ./typos + . / typos--format sarif > typos.sarif || true ''' } post { @@ -36,6 +39,7 @@ pipeline { } } } + stage('Install Dependencies') { environment { NODE_ENV = 'development' @@ -45,6 +49,7 @@ pipeline { sh 'npm install' } } + stage('Lint and Test') { environment { NODE_ENV = "development" @@ -58,6 +63,7 @@ pipeline { } } } + stage('Build PR') { when { changeRequest() @@ -71,6 +77,7 @@ pipeline { } } } + stage('Branch B') { agent { label 'linux-arm64-docker || arm64linux' @@ -89,14 +96,13 @@ pipeline { } } } + stage('Deploy PR to preview site') { when { allOf { changeRequest target: 'main' // Only deploy to production from infra.ci.jenkins.io - expression { - infra.isInfra() - } + expression { infra.isInfra() } } } environment { @@ -114,6 +120,7 @@ pipeline { } } } + stage('Build Production') { when { branch "main" @@ -122,14 +129,13 @@ pipeline { sh 'npm run build' } } + stage('Deploy Production') { when { allOf { branch "main" // Only deploy to production from infra.ci.jenkins.io - expression { - infra.isInfra() - } + expression { infra.isInfra() } } } environment { @@ -148,4 +154,4 @@ pipeline { } } } -} \ No newline at end of file +} From eb3190c84d3cc47cf70f5d1aa87e83bd5ca6f018 Mon Sep 17 00:00:00 2001 From: Omar Hussein <117474007+Eng-Omar-Hussein@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:07:32 +0200 Subject: [PATCH 07/13] Apply suggestions from code review Co-authored-by: Damien Duportal --- Jenkinsfile | 8 -------- docker-compose.yml | 6 ------ 2 files changed, 14 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index ecdb2836..8363457f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -79,20 +79,12 @@ pipeline { } stage('Branch B') { - agent { - label 'linux-arm64-docker || arm64linux' - } steps { echo 'Test Docker Compose' sh 'docker compose up --detach --wait' sh 'docker compose run --rm stories_webapp env' sh 'docker compose down' } - post { - always { - sh 'docker compose down || true' - } - } } } } diff --git a/docker-compose.yml b/docker-compose.yml index 1c4ff867..0ee5c942 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,9 +25,3 @@ services: entrypoint: [] command: bash -c "asdf install && asdf current && npm install && npm run develop" - networks: - - stories_network - -networks: - stories_network: - driver: bridge From 651f976f9a2948075971f3e59ae4e8cb7665c768 Mon Sep 17 00:00:00 2001 From: Eng-Omar-Hussein Date: Wed, 8 Apr 2026 00:49:56 +0200 Subject: [PATCH 08/13] refactor: update environment variable handling in Jenkinsfile and docker-compose.yml --- .env | 5 +-- Jenkinsfile | 100 +++++++++++++++++++++++---------------------- docker-compose.yml | 25 +++++------- 3 files changed, 63 insertions(+), 67 deletions(-) diff --git a/.env b/.env index 965bc5a2..e0202ffc 100644 --- a/.env +++ b/.env @@ -1,11 +1,8 @@ -WORKSPACE_ = "/home/jenkins/agent/workspace" +APP_WORKING_DIR = "/home/jenkins/agent/workspace" NODE_ENV = 'production' TZ = "UTC" # // Amount of available vCPUs, to avoid OOM - https://www.gatsbyjs.com/docs/how-to/performance/resolving-out-of-memory-issues/#try-reducing-the-number-of-cores # // https://github.com/jenkins-infra/jenkins-infra/tree/production/hieradata/clients/controller.ci.jenkins.io.yaml#L327 GATSBY_CPU_COUNT = "4" -# // Added the below to fix permissions issue with the cache -GATSBY_CACHE_DIR = "${WORKSPACE_}/.gatsby-cache" -GATSBY_INTERNAL_CACHE_DIR = "${WORKSPACE_}/.cache" GATSBY_TELEMETRY_DISABLED = "1" NODE_OPTIONS = "--no-warnings" diff --git a/Jenkinsfile b/Jenkinsfile index ecdb2836..df99e290 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,26 +5,30 @@ pipeline { disableConcurrentBuilds(abortPrevious: true) buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '5', numToKeepStr: '5') } - + agent { label 'linux-arm64-docker || arm64linux' } - + stages { stage('load env file') { steps { // Load environment variables from .env file. - sh ''' - set -a - source ./.env - set +a - ''' + script { + def envFile = readFile('.env') + envFile.readLines() + .findAll { it.trim() && !it.startsWith('#') && it.contains('=') } + .each { line -> + def (key, value) = line.trim().split('=', 2) + env."${key}" = value + } + } } } - - stage('Parallel Stage') { + + stage('Test and build') { parallel { - stage('Branch A') { + stage('Main CI') { stages { stage('Check for typos') { steps { @@ -39,7 +43,7 @@ pipeline { } } } - + stage('Install Dependencies') { environment { NODE_ENV = 'development' @@ -49,7 +53,7 @@ pipeline { sh 'npm install' } } - + stage('Lint and Test') { environment { NODE_ENV = "development" @@ -63,7 +67,7 @@ pipeline { } } } - + stage('Build PR') { when { changeRequest() @@ -75,52 +79,50 @@ pipeline { sh 'npm run build' } } + + stage('Deploy PR to preview site') { + when { + allOf { + changeRequest target: 'main' + // Only deploy to production from infra.ci.jenkins.io + expression { infra.isInfra() } + } + } + environment { + NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') + } + steps { + sh 'netlify-deploy --draft=true --siteName "jenkins-is-the-way" --title "Preview deploy for ${CHANGE_ID}" --alias "deploy-preview-${CHANGE_ID}" -d ./public' + } + post { + success { + recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'success', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") + } + failure { + recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'failure', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") + } + } + } } } - - stage('Branch B') { - agent { - label 'linux-arm64-docker || arm64linux' + + stage('Test Docker Compose') { + when { + allOf { + changeRequest () + // Only deploy to production from infra.ci.jenkins.io + expression { infra.isInfra() } + } } steps { - echo 'Test Docker Compose' sh 'docker compose up --detach --wait' sh 'docker compose run --rm stories_webapp env' sh 'docker compose down' } - post { - always { - sh 'docker compose down || true' - } - } - } - } - } - - stage('Deploy PR to preview site') { - when { - allOf { - changeRequest target: 'main' - // Only deploy to production from infra.ci.jenkins.io - expression { infra.isInfra() } - } - } - environment { - NETLIFY_AUTH_TOKEN = credentials('netlify-auth-token') - } - steps { - sh 'netlify-deploy --draft=true --siteName "jenkins-is-the-way" --title "Preview deploy for ${CHANGE_ID}" --alias "deploy-preview-${CHANGE_ID}" -d ./public' - } - post { - success { - recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'success', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") - } - failure { - recordDeployment('jenkins-infra', 'stories', pullRequest.head, 'failure', "https://deploy-preview-${CHANGE_ID}--jenkins-is-the-way.netlify.app") } } } - + stage('Build Production') { when { branch "main" @@ -129,7 +131,7 @@ pipeline { sh 'npm run build' } } - + stage('Deploy Production') { when { allOf { diff --git a/docker-compose.yml b/docker-compose.yml index 1c4ff867..b24b7d37 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,28 +6,25 @@ services: ports: - "8000:8000" - # Load environment variables - env_file: - - .env - # Add docker-compose-specific env vars environment: + # Set the GATSBY_CPU_COUNT:"2" or more whilst running the "gatsby build" command to increase performance using SMT. + GATSBY_CPU_COUNT: "1" CHOKIDAR_USEPOLLING: "true" PATH: /home/jenkins/.asdf/shims:/home/jenkins/.asdf/bin:$PATH NODE_ENV: development + APP_WORKING_DIR: $APP_WORKING_DIR volumes: - - .:${WORKSPACE_} + - .:$APP_WORKING_DIR - working_dir: ${WORKSPACE_} + working_dir: $APP_WORKING_DIR user: jenkins entrypoint: [] - command: bash -c "asdf install && asdf current && npm install && npm run develop" - - networks: - - stories_network - -networks: - stories_network: - driver: bridge + command: > + sh -c " + asdf install && asdf current && + npm install && + npm run develop -- -H 0.0.0.0 -p 8000 + " From 9720cbb6b78a22799452436313cd983e8b135b24 Mon Sep 17 00:00:00 2001 From: Eng-Omar-Hussein Date: Wed, 8 Apr 2026 00:56:02 +0200 Subject: [PATCH 09/13] docs: update Docker Compose usage instructions for user ID requirement --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 17b41f98..67614334 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,12 @@ You can also use Docker Compose for local development. ### How to Use 1. Ensure you have [Docker](https://www.docker.com/products/docker-desktop/) and [Docker Compose](https://docs.docker.com/compose/) installed. -2. In the project **root**, run: +2. Make sure the current user ID is **1001** to avoid errors related to access permission +3. In the project **root**, run: ```bash docker compose up ``` -3. Open [http://localhost:8000](http://localhost:8000) in your browser. +4. Open [http://localhost:8000](http://localhost:8000) in your browser. ## Code Quality Tools From d44b338c618aeb7694a3bcd25b412e76b828fc9b Mon Sep 17 00:00:00 2001 From: Eng-Omar-Hussein Date: Sat, 11 Apr 2026 19:13:29 +0200 Subject: [PATCH 10/13] refactor: streamline Jenkinsfile and enhance Docker Compose setup for permissions and environment handling --- Jenkinsfile | 40 ++++++++++------------ README.md | 9 +++-- docker-compose.yml | 82 +++++++++++++++++++++++++++++----------------- 3 files changed, 75 insertions(+), 56 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index df99e290..0b704476 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,21 +11,6 @@ pipeline { } stages { - stage('load env file') { - steps { - // Load environment variables from .env file. - script { - def envFile = readFile('.env') - envFile.readLines() - .findAll { it.trim() && !it.startsWith('#') && it.contains('=') } - .each { line -> - def (key, value) = line.trim().split('=', 2) - env."${key}" = value - } - } - } - } - stage('Test and build') { parallel { stage('Main CI') { @@ -76,7 +61,10 @@ pipeline { NODE_ENV = 'development' } steps { - sh 'npm run build' + sh ''' + source ./.env + npm run build + ''' } } @@ -109,15 +97,18 @@ pipeline { stage('Test Docker Compose') { when { allOf { - changeRequest () - // Only deploy to production from infra.ci.jenkins.io - expression { infra.isInfra() } + changeRequest() + // Only run docker tests on non-infra.ci.jenkins.io + expression { !infra.isInfra() } } } steps { - sh 'docker compose up --detach --wait' - sh 'docker compose run --rm stories_webapp env' - sh 'docker compose down' + sh ''' + source ./.env + docker compose up --detach --wait + docker compose run --rm stories_webapp env + docker compose down + ''' } } } @@ -128,7 +119,10 @@ pipeline { branch "main" } steps { - sh 'npm run build' + sh ''' + source ./.env + npm run build + ''' } } diff --git a/README.md b/README.md index 67614334..9d25d990 100644 --- a/README.md +++ b/README.md @@ -55,12 +55,15 @@ You can also use Docker Compose for local development. ### How to Use 1. Ensure you have [Docker](https://www.docker.com/products/docker-desktop/) and [Docker Compose](https://docs.docker.com/compose/) installed. -2. Make sure the current user ID is **1001** to avoid errors related to access permission -3. In the project **root**, run: +2. In the project **root**, run: ```bash docker compose up ``` -4. Open [http://localhost:8000](http://localhost:8000) in your browser. +3. Open [http://localhost:8000](http://localhost:8000) in your browser. + +> Note: You can override the number of CPUs used by Gatsby by setting the `GATSBY_CPU_COUNT` environment variable. + +> Running service `fix-permissions` to avoid `Error: EACCES: Permission denied` ## Code Quality Tools diff --git a/docker-compose.yml b/docker-compose.yml index b24b7d37..448a4af4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,30 +1,52 @@ -services: - stories_webapp: - # TODO: track version with updatecli - ref. https://github.com/jenkins-infra/jenkins-infra/blob/efe90908529525bb3c9e61c2eb920ada3b968f1a/updatecli/updatecli.d/jenkinscontroller-tools-maven.yaml#L17-L22 - image: jenkinsciinfra/jenkins-agent-ubuntu-22.04:2.91.1 - - ports: - - "8000:8000" - - environment: - # Set the GATSBY_CPU_COUNT:"2" or more whilst running the "gatsby build" command to increase performance using SMT. - GATSBY_CPU_COUNT: "1" - CHOKIDAR_USEPOLLING: "true" - PATH: /home/jenkins/.asdf/shims:/home/jenkins/.asdf/bin:$PATH - NODE_ENV: development - APP_WORKING_DIR: $APP_WORKING_DIR - - volumes: - - .:$APP_WORKING_DIR - - working_dir: $APP_WORKING_DIR - - user: jenkins - - entrypoint: [] - command: > - sh -c " - asdf install && asdf current && - npm install && - npm run develop -- -H 0.0.0.0 -p 8000 - " +services: + fix-permissions: + image: busybox + user: root + working_dir: /app + volumes: + - .:/app + + command: > + sh -c " + if ! [ -d /app/public ]; then + mkdir -p /app/public + fi + if ! [ -d /app/.cache ]; then + mkdir -p /app/.cache + fi + if ! id -u jenkins > /dev/null 2>&1; then + adduser -u 1001 -D jenkins + fi + chown -R jenkins:jenkins /app/public /app/.cache /app/node_modules + " + stories_webapp: + # TODO: track version with updatecli - ref. https://github.com/jenkins-infra/jenkins-infra/blob/efe90908529525bb3c9e61c2eb920ada3b968f1a/updatecli/updatecli.d/jenkinscontroller-tools-maven.yaml#L17-L22 + image: jenkinsciinfra/jenkins-agent-ubuntu-22.04:2.91.1 + ports: + - "8000:8000" + + environment: + # Can pass the "GATSBY_CPU_COUNT" from your shell straight through to your containers,if it is set and not empty, otherwise the default value="2" will be used to avoid OOM issues + GATSBY_CPU_COUNT: ${GATSBY_CPU_COUNT:-2} + CHOKIDAR_USEPOLLING: "true" + PATH: /home/jenkins/.asdf/shims:/home/jenkins/.asdf/bin:$PATH + NODE_ENV: development + APP_WORKING_DIR: $APP_WORKING_DIR + + volumes: + - .:$APP_WORKING_DIR + - asdf_cache:/home/jenkins/.asdf + + working_dir: $APP_WORKING_DIR + user: jenkins + entrypoint: [] + command: > + sh -c " + asdf plugin add nodejs && + asdf install && + npm install && + npm run develop -- -H 0.0.0.0 -p 8000 + " + +volumes: + asdf_cache: From 1ab18cd2aa29666c97cbc04dbabe693f2c436377 Mon Sep 17 00:00:00 2001 From: Eng-Omar-Hussein Date: Sun, 12 Apr 2026 02:14:51 +0200 Subject: [PATCH 11/13] refactor: simplify directory creation and permissions in Docker Compose setup --- docker-compose.yml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 448a4af4..512318e4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,16 +8,11 @@ services: command: > sh -c " - if ! [ -d /app/public ]; then - mkdir -p /app/public - fi - if ! [ -d /app/.cache ]; then - mkdir -p /app/.cache - fi - if ! id -u jenkins > /dev/null 2>&1; then - adduser -u 1001 -D jenkins - fi - chown -R jenkins:jenkins /app/public /app/.cache /app/node_modules + dirs='public .cache' + for d in $$dirs; do + mkdir -p $$d + chmod -R 777 $$d + done " stories_webapp: # TODO: track version with updatecli - ref. https://github.com/jenkins-infra/jenkins-infra/blob/efe90908529525bb3c9e61c2eb920ada3b968f1a/updatecli/updatecli.d/jenkinscontroller-tools-maven.yaml#L17-L22 @@ -35,6 +30,7 @@ services: volumes: - .:$APP_WORKING_DIR + - stories_node_modules:/home/jenkins/node_modules - asdf_cache:/home/jenkins/.asdf working_dir: $APP_WORKING_DIR @@ -49,4 +45,5 @@ services: " volumes: + stories_node_modules: asdf_cache: From f4672aecdd31706f10982e0d050f123d39f688fb Mon Sep 17 00:00:00 2001 From: Eng-Omar-Hussein Date: Mon, 13 Apr 2026 18:24:47 +0200 Subject: [PATCH 12/13] refactor: update working directory in .env and optimize Docker Compose setup by removing unnecessary permissions service --- .env | 2 +- README.md | 4 +--- docker-compose.yml | 26 +++++++------------------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/.env b/.env index e0202ffc..f5ff19b2 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -APP_WORKING_DIR = "/home/jenkins/agent/workspace" +APP_WORKING_DIR = "/home/jenkins/agent" NODE_ENV = 'production' TZ = "UTC" # // Amount of available vCPUs, to avoid OOM - https://www.gatsbyjs.com/docs/how-to/performance/resolving-out-of-memory-issues/#try-reducing-the-number-of-cores diff --git a/README.md b/README.md index 9d25d990..f8e4c6ab 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,7 @@ You can also use Docker Compose for local development. ``` 3. Open [http://localhost:8000](http://localhost:8000) in your browser. -> Note: You can override the number of CPUs used by Gatsby by setting the `GATSBY_CPU_COUNT` environment variable. - -> Running service `fix-permissions` to avoid `Error: EACCES: Permission denied` +> Note: You can override the number of CPUs used by Gatsby by setting the `GATSBY_CPU_COUNT` environment variable to avoid OOM. ## Code Quality Tools diff --git a/docker-compose.yml b/docker-compose.yml index 512318e4..232b161c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,4 @@ services: - fix-permissions: - image: busybox - user: root - working_dir: /app - volumes: - - .:/app - - command: > - sh -c " - dirs='public .cache' - for d in $$dirs; do - mkdir -p $$d - chmod -R 777 $$d - done - " stories_webapp: # TODO: track version with updatecli - ref. https://github.com/jenkins-infra/jenkins-infra/blob/efe90908529525bb3c9e61c2eb920ada3b968f1a/updatecli/updatecli.d/jenkinscontroller-tools-maven.yaml#L17-L22 image: jenkinsciinfra/jenkins-agent-ubuntu-22.04:2.91.1 @@ -21,16 +6,17 @@ services: - "8000:8000" environment: - # Can pass the "GATSBY_CPU_COUNT" from your shell straight through to your containers,if it is set and not empty, otherwise the default value="2" will be used to avoid OOM issues - GATSBY_CPU_COUNT: ${GATSBY_CPU_COUNT:-2} + # Can pass the "GATSBY_CPU_COUNT" from your shell straight through to your containers, if it is set and not empty, otherwise the default value will be used to avoid OOM issues + GATSBY_CPU_COUNT: ${GATSBY_CPU_COUNT:-physical_cores} CHOKIDAR_USEPOLLING: "true" PATH: /home/jenkins/.asdf/shims:/home/jenkins/.asdf/bin:$PATH NODE_ENV: development APP_WORKING_DIR: $APP_WORKING_DIR volumes: - - .:$APP_WORKING_DIR - - stories_node_modules:/home/jenkins/node_modules + - .:$APP_WORKING_DIR/workspace + - ./src:$APP_WORKING_DIR/src + - stories_node_modules:/tmp/node_modules - asdf_cache:/home/jenkins/.asdf working_dir: $APP_WORKING_DIR @@ -38,6 +24,8 @@ services: entrypoint: [] command: > sh -c " + ln -s /tmp/node_modules ${APP_WORKING_DIR}/node_modules || true && + cp -r ${APP_WORKING_DIR}/workspace/. . || true && asdf plugin add nodejs && asdf install && npm install && From 7b4bc81144e7a5fbd54d84744a1a7ae4ab85284f Mon Sep 17 00:00:00 2001 From: Omar Hussein <117474007+Eng-Omar-Hussein@users.noreply.github.com> Date: Wed, 13 May 2026 18:06:08 +0300 Subject: [PATCH 13/13] fix: update jenkins agent image version --- docker-compose.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 232b161c..9b11e5c1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: stories_webapp: # TODO: track version with updatecli - ref. https://github.com/jenkins-infra/jenkins-infra/blob/efe90908529525bb3c9e61c2eb920ada3b968f1a/updatecli/updatecli.d/jenkinscontroller-tools-maven.yaml#L17-L22 - image: jenkinsciinfra/jenkins-agent-ubuntu-22.04:2.91.1 + image: jenkinsciinfra/jenkins-agent-ubuntu-22.04:2.102.0 ports: - "8000:8000" @@ -9,7 +9,6 @@ services: # Can pass the "GATSBY_CPU_COUNT" from your shell straight through to your containers, if it is set and not empty, otherwise the default value will be used to avoid OOM issues GATSBY_CPU_COUNT: ${GATSBY_CPU_COUNT:-physical_cores} CHOKIDAR_USEPOLLING: "true" - PATH: /home/jenkins/.asdf/shims:/home/jenkins/.asdf/bin:$PATH NODE_ENV: development APP_WORKING_DIR: $APP_WORKING_DIR @@ -17,7 +16,6 @@ services: - .:$APP_WORKING_DIR/workspace - ./src:$APP_WORKING_DIR/src - stories_node_modules:/tmp/node_modules - - asdf_cache:/home/jenkins/.asdf working_dir: $APP_WORKING_DIR user: jenkins @@ -26,12 +24,11 @@ services: sh -c " ln -s /tmp/node_modules ${APP_WORKING_DIR}/node_modules || true && cp -r ${APP_WORKING_DIR}/workspace/. . || true && - asdf plugin add nodejs && - asdf install && - npm install && + node --version && + npm --version && + npm ci && npm run develop -- -H 0.0.0.0 -p 8000 " volumes: stories_node_modules: - asdf_cache: