Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 35 additions & 2 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,41 @@ jobs:
-H "Accept: application/json" \
-H "Authorization: Bearer ${{ secrets.RENDER_API_KEY }}"

sentry-release:
runs-on: ubuntu-latest
needs: [deploy-staging, deploy-prod]
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main'
steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Create and Finalize Sentry Release
uses: getsentry/action-release@v1
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
with:
version: ${{ github.sha }}
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
finalize: true
set_commits: auto

- name: Mark Release as Deployed
run: |
ENVIRONMENT=${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
VERSION=${{ github.sha }}
curl https://sentry.io/api/0/organizations/${{ secrets.SENTRY_ORG }}/releases/$VERSION/deploys/ \
-X POST \
-H "Authorization: Bearer ${{ secrets.SENTRY_AUTH_TOKEN }}" \
-H 'Content-Type: application/json' \
-d "{\"environment\":\"$ENVIRONMENT\"}"


notify:
runs-on: ubuntu-latest
needs: [build-test-scan, deploy-staging, deploy-prod]
if: always()
needs: [build-test-scan, deploy-staging, deploy-prod, sentry-release]
if: always()
steps:
- name: Slack Notification for Staging
if: github.ref == 'refs/heads/develop'
Expand All @@ -88,6 +119,7 @@ jobs:
Commit: ${{ github.sha }}
Status: ${{ job.status }}
Environment: Staging
Release: ${{ github.sha }}

- name: Slack Notification for Production
if: github.ref == 'refs/heads/main'
Expand All @@ -103,3 +135,4 @@ jobs:
Commit: ${{ github.sha }}
Status: ${{ job.status }}
Environment: Production
Release: ${{ github.sha }}
117 changes: 117 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
"author": "Your Name",
"license": "MIT",
"dependencies": {
"@sentry/node": "^7.120.4",
"@sentry/tracing": "^7.120.4",
"express": "^4.21.2"
},
"devDependencies": {
Expand All @@ -29,5 +31,15 @@
},
"directories": {
"test": "tests"
},
"jest": {
"testEnvironment": "node",
"setupFiles": [
"<rootDir>/tests/jest.setup.js"
],
"moduleNameMapper": {
"^@sentry/node$": "<rootDir>/tests/__mocks__/@sentry/node.js",
"^@sentry/tracing$": "<rootDir>/tests/__mocks__/@sentry/tracing.js"
}
}
}
32 changes: 32 additions & 0 deletions render.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
services:
- type: web
name: mydev-staging
env: docker
plan: free
branch: develop
rootDir: .
dockerfilePath: ./Dockerfile
autoDeploy: true
envVars:
- key: NODE_ENV
value: staging
- key: PORT
value: 10000
- key: SENTRY_DSN
sync: false

- type: web
name: mydev-prod
env: docker
plan: free
branch: main
rootDir: .
dockerfilePath: ./Dockerfile
autoDeploy: true
envVars:
- key: NODE_ENV
value: production
- key: PORT
value: 10000
- key: SENTRY_DSN
sync: false
28 changes: 27 additions & 1 deletion src/app.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
const express = require("express");
const Sentry = require("@sentry/node");
const Tracing = require("@sentry/tracing");

const app = express();

// Initialize Sentry (v7 API)
Sentry.init({
dsn: process.env.SENTRY_DSN || "",
integrations: [
new Tracing.Integrations.Express({ app }), // works fine with v7
],
tracesSampleRate: 1.0, // lower this in prod (e.g. 0.1)
});

// Request handler (before routes)
app.use(Sentry.Handlers.requestHandler());
app.use(Sentry.Handlers.tracingHandler());

// Example route
app.get("/", (req, res) => {
res.send("You are safe in Wizfi's pipeline");
res.send("You are safe in Wizfi's Pipeline!");
});

// Debug route to test Sentry (ESLint safe)
app.get("/debug-sentry", (req, res) => {
res.status(500).send("Triggering Sentry debug error...");
throw new Error("Debug Sentry error!");
});

// Error handler (after routes)
app.use(Sentry.Handlers.errorHandler());

module.exports = app;
9 changes: 9 additions & 0 deletions tests/__mocks__/@sentry/node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
init: jest.fn(),
Handlers: {
requestHandler: () => (req, res, next) => next(),
tracingHandler: () => (req, res, next) => next(),
errorHandler: () => (err, req, res, next) => next(err),
},
Integrations: {},
};
7 changes: 7 additions & 0 deletions tests/__mocks__/@sentry/tracing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
Integrations: {
Express: function () {
return {};
},
},
};
12 changes: 9 additions & 3 deletions tests/index.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
const request = require("supertest");
const app = require("../src/app");

describe("GET /", () => {
it("should return Hello message", async () => {
describe("App Routes", () => {
it("should return Hello from Wizfi pipeline!", async () => {
const res = await request(app).get("/");
expect(res.text).toBe("You are safe in Wizfi's pipeline");
expect(res.statusCode).toBe(200);
expect(res.text).toBe("You are safe in Wizfi's Pipeline!");
});

it("should handle a 404 route", async () => {
const res = await request(app).get("/not-found");
expect(res.statusCode).toBe(404);
});
});
2 changes: 2 additions & 0 deletions tests/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Fake DSN so Sentry.init() doesn't crash in test runs
process.env.SENTRY_DSN = "http://fake-dsn.local";
Loading