diff --git a/.github/workflows/build.yaml b/.github/workflows/build similarity index 100% rename from .github/workflows/build.yaml rename to .github/workflows/build diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr similarity index 100% rename from .github/workflows/build-pr.yml rename to .github/workflows/build-pr diff --git a/Jenkins/Build.Jenkinsfile b/Jenkins/Build.Jenkinsfile new file mode 100644 index 00000000..75228a90 --- /dev/null +++ b/Jenkins/Build.Jenkinsfile @@ -0,0 +1,104 @@ +// Declarative Pipeline for building Node.js application and running SonarQube analysis. +pipeline { + // Defines the execution environment. Replace 'linux-agent' with your specific agent label. + agent { + label 'linux-agent' + } + + // Configure options, primarily to ensure full Git history is fetched for SonarQube and versioning. + options { + // Skip the default checkout to manage it explicitly and ensure fetch-depth: 0. + skipDefaultCheckout() + } + + stages { + // Stage 1: Checkout the code with full history (fetch-depth: 0) + stage('Source Checkout') { + steps { + script { + // This performs a deep clone (fetch-depth: 0) + // NOTE: You must replace 'YOUR_GIT_CREDENTIALS_ID' with the actual Jenkins credential ID + // that has access to your repository. If using Anonymous checkout, remove the credentialsId line. + checkout([ + $class: 'GitSCM', + branches: [[name: 'HEAD']], + extensions: [ + [$class: 'WipeWorkspace'], + [$class: 'CleanBeforeCheckout'], + [$class: 'CloneOption', depth: 0, noTags: false, reference: '', shallow: false] + ], + userRemoteConfigs: [ + [url: env.GIT_URL ?: ''] // Replace env.GIT_URL if needed + ] + ]) + } + } + } + + // Stage 2: Setup Node.js v20 and install pnpm + stage('Setup Environment') { + steps { + sh ''' + # Install Node.js v20 (closest matching the specified version '20.17.0') + # This uses Nodesource to ensure a specific major version is available. + curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - + sudo apt-get install -y nodejs + + echo "Node.js version: \$(node -v)" + + # Install pnpm globally (version 8) + npm install -g pnpm@8 + echo "pnpm version: \$(pnpm -v)" + ''' + + // Skipping the complex pnpm cache setup as it relies on specific GitHub Actions features. + // In Jenkins, artifact caching is typically handled differently (e.g., using dedicated workspace cache plugins). + } + } + + // Stage 3: Install dependencies and build the application + stage('Install and Build') { + steps { + sh 'pnpm install' + sh 'pnpm run build' + } + } + + // Stage 4: Retrieve secrets from Vault and run SonarQube analysis + stage('SonarQube Analysis') { + steps { + script { + // 1. Get the short 8-character commit SHA for project versioning + def commitShaShort = sh(returnStdout: true, script: 'git rev-parse --short=8 HEAD').trim() + echo "Commit SHA (short) is: ${commitShaShort}" + + // 2. Retrieve secrets from HashiCorp Vault using the dedicated plugin binding. + // The secret values will be available as the environment variables SONAR_TOKEN and SONAR_HOST_URL + // only within this 'withCredentials' block. + withCredentials([ + // The $class: 'VaultSecretCredentialsBinding' requires the Jenkins HashiCorp Vault Plugin + [$class: 'VaultSecretCredentialsBinding', + vaultSecrets: [ + // Map key 'SONAR_TOKEN' from Vault path 'postiz/data/ci/sonar' to Jenkins environment variable 'SONAR_TOKEN' + [$class: 'VaultSecret', secretPath: 'postiz/data/ci/sonar', secretKey: 'SONAR_TOKEN', envVar: 'SONAR_TOKEN'], + // Map key 'SONAR_HOST_URL' from Vault path 'postiz/data/ci/sonar' to Jenkins environment variable 'SONAR_HOST_URL' + [$class: 'VaultSecret', secretPath: 'postiz/data/ci/sonar', secretKey: 'SONAR_HOST_URL', envVar: 'SONAR_HOST_URL'] + ]] + ]) { + // 3. Execute sonar-scanner CLI + // NOTE: sonar-scanner must be installed and available on the agent's PATH, + // or configured via Jenkins' Global Tool Configuration. + sh """ + echo "Starting SonarQube Analysis for project version: ${commitShaShort}" + sonar-scanner \\ + -Dsonar.projectVersion=${commitShaShort} \\ + -Dsonar.token=\${SONAR_TOKEN} \\ + -Dsonar.host.url=\${SONAR_HOST_URL} + # Add other analysis properties here if needed (e.g., -Dsonar.projectKey=...) + """ + } + } + } + } + } +} diff --git a/Jenkins/BuildPR.Jenkinsfile b/Jenkins/BuildPR.Jenkinsfile new file mode 100644 index 00000000..12be0457 --- /dev/null +++ b/Jenkins/BuildPR.Jenkinsfile @@ -0,0 +1,108 @@ +// Declarative Pipeline for building Node.js application and running SonarQube analysis for a Pull Request. +pipeline { + // Defines the execution environment. Replace 'linux-agent' with your specific agent label. + agent { + label 'linux-agent' + } + + // Configure options, primarily to ensure full Git history is fetched for SonarQube and versioning. + options { + // Skip the default checkout to manage it explicitly and ensure fetch-depth: 0. + skipDefaultCheckout() + } + + // Environment variables that hold PR details (set automatically by Jenkins SCM plugins like Git/GitHub Branch Source) + environment { + // These variables are provided by Jenkins (e.g., in a Multibranch Pipeline setup) + // CHANGE_ID corresponds to ${{ github.event.pull_request.number }} + // CHANGE_BRANCH corresponds to ${{ github.event.pull_request.head.ref }} + // CHANGE_TARGET corresponds to ${{ github.event.pull_request.base.ref }} + PR_KEY = env.CHANGE_ID + PR_BRANCH = env.CHANGE_BRANCH + PR_BASE = env.CHANGE_TARGET + } + + stages { + // Stage 1: Checkout the code with full history (fetch-depth: 0) + stage('Source Checkout') { + steps { + script { + // This performs a deep clone (fetch-depth: 0) + // NOTE: You must replace 'YOUR_GIT_CREDENTIALS_ID' with the actual Jenkins credential ID + // that has access to your repository. + checkout([ + $class: 'GitSCM', + branches: [[name: 'HEAD']], + extensions: [ + [$class: 'WipeWorkspace'], + [$class: 'CleanBeforeCheckout'], + [$class: 'CloneOption', depth: 0, noTags: false, reference: '', shallow: false] + ], + userRemoteConfigs: [ + [url: env.GIT_URL ?: ''] + ] + ]) + } + } + } + + // Stage 2: Setup Node.js v20 and install pnpm + stage('Setup Environment') { + steps { + sh ''' + # Install Node.js v20 (closest matching the specified version '20.17.0') + curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - + sudo apt-get install -y nodejs + + echo "Node.js version: \$(node -v)" + + # Install pnpm globally (version 8) + npm install -g pnpm@8 + echo "pnpm version: \$(pnpm -v)" + ''' + } + } + + // Stage 3: Install dependencies and build the application + stage('Install and Build') { + steps { + sh 'pnpm install' + sh 'pnpm run build' + } + } + + // Stage 4: Retrieve secrets from Vault and run SonarQube PR analysis + stage('SonarQube Pull Request Analysis') { + steps { + script { + // 1. Get the short 8-character commit SHA for project versioning + def commitShaShort = sh(returnStdout: true, script: 'git rev-parse --short=8 HEAD').trim() + echo "Commit SHA (short) is: ${commitShaShort}" + + // 2. Retrieve secrets from HashiCorp Vault using the dedicated plugin binding. + withCredentials([ + // Requires the Jenkins HashiCorp Vault Plugin + [$class: 'VaultSecretCredentialsBinding', + vaultSecrets: [ + [$class: 'VaultSecret', secretPath: 'postiz/data/ci/sonar', secretKey: 'SONAR_TOKEN', envVar: 'SONAR_TOKEN'], + [$class: 'VaultSecret', secretPath: 'postiz/data/ci/sonar', secretKey: 'SONAR_HOST_URL', envVar: 'SONAR_HOST_URL'] + ]] + ]) { + // 3. Execute sonar-scanner CLI with Pull Request parameters + sh """ + echo "Starting SonarQube Pull Request Analysis for PR #${PR_KEY}" + sonar-scanner \\ + -Dsonar.projectVersion=${commitShaShort} \\ + -Dsonar.token=\${SONAR_TOKEN} \\ + -Dsonar.host.url=\${SONAR_HOST_URL} \\ + -Dsonar.pullrequest.key=${PR_KEY} \\ + -Dsonar.pullrequest.branch=${PR_BRANCH} \\ + -Dsonar.pullrequest.base=${PR_BASE} + # Add other analysis properties here if needed (e.g., -Dsonar.projectKey=...) + """ + } + } + } + } + } +} diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index e7a614d0..00000000 --- a/Jenkinsfile +++ /dev/null @@ -1,70 +0,0 @@ -pipeline { - agent any - - environment { - NODE_VERSION = '20.17.0' - PR_NUMBER = "${env.CHANGE_ID}" // PR number comes from webhook payload - IMAGE_TAG="ghcr.io/gitroomhq/postiz-app-pr:${env.CHANGE_ID}" - } - - stages { - stage('Checkout Repository') { - steps { - checkout scm - } - } - - stage('Check Node.js and npm') { - steps { - script { - sh "node -v" - sh "npm -v" - } - } - } - - stage('Install Dependencies') { - steps { - sh 'npm ci' - } - } - - stage('Build Project') { - steps { - sh 'npm run build' - } - } - - stage('Build and Push Docker Image') { - when { - expression { return env.CHANGE_ID != null } // Only run if it's a PR - } - steps { - withCredentials([string(credentialsId: 'gh-pat', variable: 'GITHUB_PASS')]) { - // Docker login step - sh ''' - echo "$GITHUB_PASS" | docker login ghcr.io -u "egelhaus" --password-stdin - ''' - // Build Docker image - sh ''' - docker build -f Dockerfile.dev -t $IMAGE_TAG . - ''' - // Push Docker image to GitHub Container Registry - sh ''' - docker push $IMAGE_TAG - ''' - } - } - } - } - post { - success { - echo 'Build completed successfully!' - - } - failure { - echo 'Build failed!' - - } - } -}