diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000..fb8e3cce48 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,200 @@ +pipeline { + agent any + + environment { + // Node.js environment + NODE_VERSION = '20' + PNPM_VERSION = '9' + + // Build paths + WORKSPACE_DIR = "${WORKSPACE}" + BUILD_OUTPUT = "${BUILD_URL}artifact/output" + } + + options { + skipDefaultCheckout() + buildDiscarder(logRotator(numToKeepStr: '10')) + timeout(time: 30, unit: 'MINUTES') + } + + stages { + stage('Checkout') { + steps { + checkout scm + script { + echo "Branch: ${env.BRANCH_NAME}" + echo "Commit: ${GIT_COMMIT.take(8)}" + } + } + } + + stage('Setup Node.js') { + steps { + nvm(nodeVersion: NODE_VERSION) { + sh 'node --version' + sh 'npm install -g pnpm@${PNPM_VERSION}' + sh 'pnpm --version' + } + } + } + + stage('Install Dependencies') { + steps { + sh 'pnpm install --frozen-lockfile' + } + } + + stage('Type Check') { + steps { + sh 'pnpm run typecheck' + } + } + + stage('Lint') { + steps { + sh 'pnpm run lint' + } + post { + always { + recordIssues( + tools: [eslint(pattern: 'node_modules/.cache/eslint/**/*')] + ) + } + } + } + + stage('Test') { + steps { + sh 'pnpm run test' + } + post { + always { + junit 'junit.xml' + publishHTML([ + reportDir: 'coverage', + reportFiles: 'index.html', + reportName: 'Coverage Report' + ]) + } + } + } + + stage('Build') { + steps { + sh 'pnpm run build' + } + archiveArtifacts( + artifacts: 'build/**/*', + fingerprint: true, + allowEmptyArchive: true + ) + } + + stage('Docker Validation') { + steps { + script { + echo 'Validating Docker production build...' + sh 'docker build --target bolt-ai-production . --no-cache --progress=plain' + echo '✅ Production target builds successfully' + } + } + } + + stage('Docker Development Build') { + steps { + script { + echo 'Validating Docker development build...' + sh 'docker build --target development . --no-cache --progress=plain' + echo '✅ Development target builds successfully' + } + } + } + + stage('Docker Compose Validation') { + steps { + script { + echo 'Validating docker-compose configuration...' + sh 'docker compose config --quiet' + echo '✅ docker-compose configuration is valid' + } + } + } + + stage('Electron Build (Optional)') { + when { branch 'main' } + steps { + sh 'pnpm run electron:build:deps || true' + } + } + } + + post { + success { + emailext( + subject: "✅ Build Successful: ${env.JOB_NAME} #${env.BUILD_NUMBER}", + body: """ +

Build Successful

+

Job: ${env.JOB_NAME}

+

Build: #${env.BUILD_NUMBER}

+

Branch: ${env.BRANCH_NAME}

+

Duration: ${currentBuild.durationString}

+

Status: SUCCESS

+

Console: View Console

+ """, + mimeType: 'text/html', + recipientProviders: [[$class: 'RequesterRecipientProvider']] + ) + } + + failure { + emailext( + subject: "❌ Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}", + body: """ +

Build Failed

+

Job: ${env.JOB_NAME}

+

Build: #${env.BUILD_NUMBER}

+

Branch: ${env.BRANCH_NAME}

+

Duration: ${currentBuild.durationString}

+

Status: FAILED

+

Console: View Console

+

Error: ${currentBuild.rawBuild?.description ?: 'See console output'}

+ """, + mimeType: 'text/html', + recipientProviders: [[$class: 'RequesterRecipientProvider']] + ) + } + + unstable { + emailext( + subject: "⚠️ Build Unstable: ${env.JOB_NAME} #${env.BUILD_NUMBER}", + body: """ +

Build Unstable

+

Job: ${env.JOB_NAME}

+

Build: #${env.BUILD_NUMBER}

+

Branch: ${env.BRANCH_NAME}

+

Duration: ${currentBuild.durationString}

+

Console: View Console

+ """, + mimeType: 'text/html', + recipientProviders: [[$class: 'RequesterRecipientProvider']] + ) + } + + always { + cleanWs( + cleanWhenAborted: true, + cleanWhenFailure: true, + cleanWhenNotBuilt: true, + cleanWhenSuccess: true, + deleteDirs: true, + notFailBuild: true, + patterns: [ + [pattern: '.gitignore', type: 'EXCLUDE'], + [pattern: 'build/**/*', type: 'EXCLUDE'], + [pattern: 'coverage/**/*', type: 'EXCLUDE'] + ] + ) + } + } +} + diff --git a/jenkins-docker-compose.yaml b/jenkins-docker-compose.yaml new file mode 100644 index 0000000000..575b145675 --- /dev/null +++ b/jenkins-docker-compose.yaml @@ -0,0 +1,39 @@ +version: '3.8' + +services: + jenkins: + image: jenkins/jenkins:lts-jdk17 + container_name: gamechanger-jenkins + restart: unless-stopped + ports: + - "8080:8080" + - "50000:50000" + volumes: + - jenkins_home:/var/jenkins_home + - /var/run/docker.sock:/var/run/docker.sock + - ./build:/var/jenkins_home/workspace/build-output + environment: + - JENKINS_OPTS=--prefix=/jenkins + - JAVA_OPTS=-Dhudson.security.csrf.GlobalCrumbIssuerConfiguration=false + networks: + - jenkins_network + + jenkins-agent: + image: jenkins/agent:latest-jdk17 + container_name: gamechanger-jenkins-agent + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - jenkins + networks: + - jenkins_network + +networks: + jenkins_network: + driver: bridge + +volumes: + jenkins_home: + driver: local + diff --git a/jenkins-job-config.xml b/jenkins-job-config.xml new file mode 100644 index 0000000000..4c02c441aa --- /dev/null +++ b/jenkins-job-config.xml @@ -0,0 +1,184 @@ + + + GameChanger CI/CD Pipeline - Automated build and test for the AI-Powered Video Game Development Platform + false + + + https://github.com/your-org/gamechanger/ + + + + + + NODE_VERSION + Node.js version to use + 20 + false + + + PNPM_VERSION + pnpm version to use + 9 + false + + RUN_DOCKER_BUILD + Whether to validate Docker builds + true + + + RUN_ELECTRON_BUILD + Whether to build Electron packages (main branch only) + true + + + + + + + + + + + + + + H 0 * * * + + + + + docker-agent + 5 + false + false + + + -1 + + 2 + + + https://github.com/your-org/gamechanger.git + github-credentials + + + + + + */main + + + false + + + + true + false + false + false + + + + + + + + false + + + + true + + + + + junit.xml + 1.0 + true + + + + + Coverage Report + coverage + index.html + true + false + + + + + + + SUCCESS + 0 + BLUE + true + + + + + + + 30 + MINUTES + + + + + diff --git a/jenkins.Dockerfile b/jenkins.Dockerfile new file mode 100644 index 0000000000..50dc6f434a --- /dev/null +++ b/jenkins.Dockerfile @@ -0,0 +1,42 @@ +FROM jenkins/inbound-agent:alpine-jdk17 + +# Install Node.js and required tools +RUN apk add --no-cache \ + nodejs \ + npm \ + git \ + curl \ + docker \ + docker-cli-compose \ + bash \ + openssl \ + ca-certificates \ + && apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/v3.19/community \ + nodejs-current \ + npm + +# Install specific Node.js version +ENV NODE_VERSION=20 +ENV NVM_DIR=/usr/local/nvm + +RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash \ + && . $NVM_DIR/nvm.sh \ + && nvm install $NODE_VERSION \ + && nvm use $NODE_VERSION \ + && nvm alias default $NODE_VERSION + +# Install pnpm globally +RUN . $NVM_DIR/nvm.sh && npm install -g pnpm@9 + +# Set Node.js paths +ENV PATH=$NVM_DIR/versions/node/v${NODE_VERSION}/bin:$PATH + +# Create workspace directory +RUN mkdir -p /home/jenkins/agent/workspace + +# Set working directory +WORKDIR /home/jenkins/agent + +# Default command +CMD ["sh"] +