Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
2b675c8
Add initial GitHub Actions workflow - test job
Dipendra-666 Feb 12, 2026
5d85f85
Fix YAML syntax, indentation and naming in test job
Dipendra-666 Feb 12, 2026
430ae5c
include the package-lock.json file
Dipendra-666 Feb 12, 2026
4778d6e
just added the forceExit on yml
Dipendra-666 Feb 12, 2026
d0abd3a
implemented the matrix strategy across different os environment and n…
Dipendra-666 Feb 12, 2026
8474bdd
added npm caching for the faster matrix build
Dipendra-666 Feb 12, 2026
6d420e3
this should hit the cache now
Dipendra-666 Feb 12, 2026
0d4d104
Add build script for artifact demo
Dipendra-666 Feb 12, 2026
bc76913
Add build job + upload artifact
Dipendra-666 Feb 12, 2026
1d54a7e
Add deploy-staging and deploy-prod jobs with OIDC and environments
Dipendra-666 Feb 12, 2026
a1d4c87
Add id-token write permission for OIDC login
Dipendra-666 Feb 13, 2026
2612f61
Added the app name with unique value to the staging and production
Dipendra-666 Feb 13, 2026
7c6f1ca
Test after adding environment-based federated credentials
Dipendra-666 Feb 13, 2026
8e31960
please run bro
Dipendra-666 Feb 13, 2026
9be2301
give the full domain name
Dipendra-666 Feb 13, 2026
c462c2e
just debugging
Dipendra-666 Feb 13, 2026
6615001
added the short name of the webapp instead of the name with the uniqu…
Dipendra-666 Feb 16, 2026
6cf24a6
Fix build script: clean dist before copy and include node_modules
Dipendra-666 Feb 16, 2026
e4c33c2
added and make changes into the README file
Dipendra-666 Feb 16, 2026
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
147 changes: 147 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
name: CI/CD Showcase Pipeline

permissions:
id-token: write
contents: read

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:

jobs:
test:
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18,20]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: cache npm dependencies
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-{{ matrix.node-version }}-

- name: Install dependencies
run: npm ci

- name: Run linting
run: npm run lint

- name: Run unit tests
run: npm test -- --forceExit

build:
needs: test
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-20.x-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-20.x-

- name: Install dependencies
run: npm ci

- name: Run build
run: npm run build

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: app-build
path: dist/

deploy-staging:
needs: build
runs-on: ubuntu-latest
environment: staging

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Download artifact
uses: actions/download-artifact@v4
with:
name: app-build
path: dist/

- name: Login to Azure
uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

- name: Deploy to Staging
uses: azure/webapps-deploy@v3
with:
app-name: dipendra-staging-app
package: dist/

- name: Debug - List App Services in RG
run: az webapp list --resource-group dipendra-rg --query "[].name" -o table

- name: Debug - List all App Services in subscription
run: az webapp list --query "[].{Name:name, ResourceGroup:resourceGroup, Location:location}" -o table

deploy-prod:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Download artifact
uses: actions/download-artifact@v4
with:
name: app-build
path: dist/

- name: Login to Azure
uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

- name: Deploy to Production
uses: azure/webapps-deploy@v3
with:
app-name: dipendra-production-app
package: dist/
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ node_modules
jspm_packages

# Optional npm cache directory
.npm


# Optional REPL history
.node_repl_history
package-lock.json
93 changes: 79 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,83 @@
---
page_type: sample
languages:
- nodejs
- javascript
products:
- azure
- azure-app-service
description: "This sample demonstrates a tiny Hello World Node.js app for Azure App Service."
---
# CI/CD Pipeline Showcase – Node.js App to Azure App Service

# Node.js Hello World
Full end-to-end CI/CD pipeline built with GitHub Actions, deploying a simple Node.js "Hello World" Express app to Azure App Service (staging + production environments).

This sample demonstrates a tiny Hello World node.js app for [App Service Web App](https://docs.microsoft.com/azure/app-service-web).
This project demonstrates modern DevOps practices suitable for mid-level roles: automated testing, caching, artifact management, secure authentication (OIDC), multi-environment deployment, and gated production releases.

## Contributing
## Features

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
- **CI**:
- Parallel matrix testing (Node 18 & 20 × Ubuntu & Windows-latest)
- ESLint linting
- Jest unit/integration tests
- npm caching for fast builds

- **Build & Artifact**:
- Single build job on Node 20
- Creates `dist/` folder → uploads as artifact

- **CD**:
- Secure login to Azure using **OIDC federation** (no secrets in repo)
- Auto-deploy to **staging** environment
- Manual approval gate before deploy to **production**
- Real deployment to Azure App Service (Linux, Node 22 LTS)

## Architecture / Flow

1. Push or PR to `main` → trigger workflow
2. Run test matrix (4 jobs) → lint + unit tests
3. Build job → `npm run build` → upload `dist/` artifact
4. Deploy to **staging** (automatic, no approval)
5. Deploy to **production** (pauses → requires manual approval from me)
6. Live on Azure: staging auto-updates, production gated

## Screenshots

### 1. Full GitHub Actions Workflow Run
Shows matrix testing (4 jobs), build, artifact upload, staging deploy, and production waiting for manual review.

![GitHub Actions workflow run – full pipeline overview](images/image1.png)

### 2. Live Staging App
"Hello World!" successfully deployed to staging environment (auto-deploy).

![Staging app live – Hello World!](images/image2.png)

### 3. Complete Successful Run (after approving production)
All jobs green – production deployed after manual approval.

![Full pipeline success – production deployed](images/image3.png)

## Technologies Used

- GitHub Actions
- Azure App Service (F1 free tier, Linux, Node 22 LTS)
- OIDC (OpenID Connect) workload identity federation
- Node.js + Express
- ESLint + Jest + Supertest
- npm caching & artifacts

## Repository Structure (important files)

- `.github/workflows/ci-cd.yml` → full pipeline definition
- `index.js` → simple Express server
- `package.json` → scripts, deps, build command
- `dist/` → build output (index.js + package.json + node_modules)

## Lessons Learned

- F1 free tier quota limits (60 CPU min/day) → can disable site after repeated deploys/tests
- Azure App Service cold starts + runtime `npm install` can cause initial 504/Application Error
- OIDC setup (federated credentials for branch + environments) is more secure than secrets
- Manual approval gates in production are essential for real-world safety
- **Jest hanging / open handle error** → fixed with `--forceExit` flag on `npm test` to force exit after tests

## How to Run Locally

```bash
npm install
npm run build
npm start


Visit http://localhost:3000 → "Hello World!"
Loading