diff --git a/code/sample-nodejs-app/Dockerfile b/code/sample-nodejs-app/Dockerfile new file mode 100644 index 0000000..48eb829 --- /dev/null +++ b/code/sample-nodejs-app/Dockerfile @@ -0,0 +1,16 @@ +# Build stage +FROM node:18-slim AS builder +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . + +# Production stage +FROM node:18-slim +WORKDIR /app +COPY --from=builder /app/package*.json ./ +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/index.js ./ + +EXPOSE 3000 +CMD ["node", "index.js"] diff --git a/code/sample-nodejs-app/Jenkinsfile b/code/sample-nodejs-app/Jenkinsfile new file mode 100644 index 0000000..9b37ba1 --- /dev/null +++ b/code/sample-nodejs-app/Jenkinsfile @@ -0,0 +1,67 @@ +pipeline { + agent any + + environment { + APP_NAME = 'sample-nodejs-app' + DOCKER_IMAGE = "test-cicd/${APP_NAME}:${env.BUILD_NUMBER}" + } + + stages { + stage('Checkout') { + steps { + checkout scm + } + } + + stage('Install Dependencies') { + steps { + dir('code/sample-nodejs-app') { + sh 'npm install' + } + } + } + + stage('Test') { + steps { + dir('code/sample-nodejs-app') { + sh 'npm test' + } + } + } + + stage('Build Docker Image') { + steps { + dir('code/sample-nodejs-app') { + sh "docker build -t ${APP_NAME}:latest ." + } + } + } + + stage('Push to Registry') { + steps { + echo 'Pushing image to registry...' + // sh "docker tag ${APP_NAME}:latest ${DOCKER_IMAGE}" + // sh "docker push ${DOCKER_IMAGE}" + } + } + + stage('Deploy to K8s') { + steps { + echo 'Deploying to Kubernetes...' + // sh "kubectl set image deployment/${APP_NAME} ${APP_NAME}=${DOCKER_IMAGE}" + } + } + } + + post { + always { + cleanWs() + } + success { + echo 'Pipeline completed successfully!' + } + failure { + echo 'Pipeline failed!' + } + } +} diff --git a/code/sample-nodejs-app/index.js b/code/sample-nodejs-app/index.js new file mode 100644 index 0000000..7ece4f8 --- /dev/null +++ b/code/sample-nodejs-app/index.js @@ -0,0 +1,23 @@ +const express = require('express'); +const app = express(); +const port = process.env.PORT || 3000; + +app.get('/', (req, res) => { + res.json({ + message: 'Hello World from Antigravity!', + status: 'success', + timestamp: new Date().toISOString() + }); +}); + +app.get('/health', (req, res) => { + res.status(200).send('OK'); +}); + +if (require.main === module) { + app.listen(port, () => { + console.log(`Server is running on port ${port}`); + }); +} + +module.exports = app; diff --git a/code/sample-nodejs-app/package.json b/code/sample-nodejs-app/package.json new file mode 100644 index 0000000..c3528da --- /dev/null +++ b/code/sample-nodejs-app/package.json @@ -0,0 +1,17 @@ +{ + "name": "sample-nodejs-app", + "version": "1.0.0", + "description": "A sample Node.js app for CI/CD demonstration", + "main": "index.js", + "scripts": { + "start": "node index.js", + "test": "jest" + }, + "dependencies": { + "express": "^4.18.2" + }, + "devDependencies": { + "jest": "^29.5.0", + "supertest": "^6.3.3" + } +} diff --git a/code/sample-nodejs-app/test/app.test.js b/code/sample-nodejs-app/test/app.test.js new file mode 100644 index 0000000..3655964 --- /dev/null +++ b/code/sample-nodejs-app/test/app.test.js @@ -0,0 +1,19 @@ +const request = require('supertest'); +const app = require('../index'); + +describe('GET /', () => { + it('should return 200 OK and a welcome message', async () => { + const res = await request(app).get('/'); + expect(res.statusCode).toEqual(200); + expect(res.body).toHaveProperty('message'); + expect(res.body.message).toContain('Hello World'); + }); +}); + +describe('GET /health', () => { + it('should return 200 OK', async () => { + const res = await request(app).get('/health'); + expect(res.statusCode).toEqual(200); + expect(res.text).toEqual('OK'); + }); +});