seqpulse 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,221 @@
1
+ # CI/CD Snippets Multi-Platform
2
+
3
+ Snippets de reference pour integrer `SeqPulse` avec la meme logique sur plusieurs plateformes CI/CD:
4
+
5
+ 1. `trigger` avant le deploy
6
+ 2. deploy applicatif
7
+ 3. `finish` toujours execute, meme en cas d'echec
8
+
9
+ Tous les snippets ci-dessous utilisent le package publie `@nassir_gouomba/seqpulse@0.5.0` et la sortie ciblee `--output deploymentId`.
10
+
11
+ ## Variables requises
12
+
13
+ Definir ces secrets/variables dans votre plateforme CI:
14
+
15
+ - `SEQPULSE_BASE_URL`
16
+ - `SEQPULSE_API_KEY`
17
+ - `SEQPULSE_METRICS_ENDPOINT`
18
+
19
+ ## Design cible
20
+
21
+ - `trigger` reste non bloquant pour ne pas casser le deploy si SeqPulse est indisponible
22
+ - `deploymentId` est capture dans une variable CI, pas dans un JSON parse fragile
23
+ - `finish` recoit un statut explicite venant de la plateforme
24
+
25
+ ## GitHub Actions
26
+
27
+ ```yaml
28
+ name: deploy
29
+
30
+ on:
31
+ push:
32
+ branches: [main]
33
+
34
+ jobs:
35
+ deploy:
36
+ runs-on: ubuntu-latest
37
+ env:
38
+ SEQPULSE_BASE_URL: ${{ secrets.SEQPULSE_BASE_URL }}
39
+ SEQPULSE_API_KEY: ${{ secrets.SEQPULSE_API_KEY }}
40
+ SEQPULSE_METRICS_ENDPOINT: ${{ secrets.SEQPULSE_METRICS_ENDPOINT }}
41
+
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+
45
+ - uses: actions/setup-node@v4
46
+ with:
47
+ node-version: 20
48
+ cache: npm
49
+
50
+ - name: Install
51
+ run: npm ci
52
+
53
+ - name: SeqPulse Trigger
54
+ id: seqpulse_trigger
55
+ run: |
56
+ DEPLOYMENT_ID="$(npx -y @nassir_gouomba/seqpulse@0.5.0 ci trigger \
57
+ --env prod \
58
+ --branch "${GITHUB_REF_NAME}" \
59
+ --non-blocking true \
60
+ --output deploymentId)"
61
+ echo "deployment_id=${DEPLOYMENT_ID}" >> "$GITHUB_OUTPUT"
62
+
63
+ - name: Deploy
64
+ run: ./deploy.sh
65
+
66
+ - name: SeqPulse Finish
67
+ if: ${{ always() }}
68
+ run: |
69
+ npx -y @nassir_gouomba/seqpulse@0.5.0 ci finish \
70
+ --deployment-id "${{ steps.seqpulse_trigger.outputs.deployment_id }}" \
71
+ --job-status "${{ job.status }}" \
72
+ --non-blocking true
73
+ ```
74
+
75
+ ## GitLab CI
76
+
77
+ ```yaml
78
+ deploy_prod:
79
+ image: node:20
80
+ stage: deploy
81
+ script:
82
+ - npm ci
83
+ - |
84
+ DEPLOYMENT_ID="$(npx -y @nassir_gouomba/seqpulse@0.5.0 ci trigger \
85
+ --env prod \
86
+ --branch "${CI_COMMIT_REF_NAME}" \
87
+ --non-blocking true \
88
+ --output deploymentId)"
89
+ printf 'SEQPULSE_DEPLOYMENT_ID=%s\n' "$DEPLOYMENT_ID" > .seqpulse.env
90
+ - ./deploy.sh
91
+ after_script:
92
+ - . ./.seqpulse.env 2>/dev/null || true
93
+ - |
94
+ npx -y @nassir_gouomba/seqpulse@0.5.0 ci finish \
95
+ --deployment-id "${SEQPULSE_DEPLOYMENT_ID}" \
96
+ --job-status "${CI_JOB_STATUS}" \
97
+ --non-blocking true
98
+ ```
99
+
100
+ ## CircleCI
101
+
102
+ ```yaml
103
+ version: 2.1
104
+
105
+ jobs:
106
+ deploy:
107
+ docker:
108
+ - image: cimg/node:20.11
109
+ steps:
110
+ - checkout
111
+
112
+ - run:
113
+ name: Install
114
+ command: npm ci
115
+
116
+ - run:
117
+ name: SeqPulse Trigger
118
+ command: |
119
+ DEPLOYMENT_ID="$(npx -y @nassir_gouomba/seqpulse@0.5.0 ci trigger \
120
+ --env prod \
121
+ --branch "${CIRCLE_BRANCH}" \
122
+ --non-blocking true \
123
+ --output deploymentId)"
124
+ echo "export SEQPULSE_DEPLOYMENT_ID=${DEPLOYMENT_ID}" >> "$BASH_ENV"
125
+
126
+ - run:
127
+ name: Deploy
128
+ command: |
129
+ set +e
130
+ ./deploy.sh
131
+ DEPLOY_EXIT_CODE=$?
132
+ if [ "$DEPLOY_EXIT_CODE" -eq 0 ]; then
133
+ echo 'export SEQPULSE_JOB_STATUS=success' >> "$BASH_ENV"
134
+ else
135
+ echo 'export SEQPULSE_JOB_STATUS=failed' >> "$BASH_ENV"
136
+ fi
137
+ exit "$DEPLOY_EXIT_CODE"
138
+
139
+ - run:
140
+ name: SeqPulse Finish
141
+ when: always
142
+ command: |
143
+ . "$BASH_ENV"
144
+ npx -y @nassir_gouomba/seqpulse@0.5.0 ci finish \
145
+ --deployment-id "${SEQPULSE_DEPLOYMENT_ID}" \
146
+ --job-status "${SEQPULSE_JOB_STATUS:-failed}" \
147
+ --non-blocking true
148
+ ```
149
+
150
+ ## Jenkins
151
+
152
+ ```groovy
153
+ pipeline {
154
+ agent any
155
+
156
+ options {
157
+ disableConcurrentBuilds()
158
+ timestamps()
159
+ timeout(time: 20, unit: 'MINUTES')
160
+ }
161
+
162
+ environment {
163
+ SEQPULSE_BASE_URL = credentials('seqpulse_base_url')
164
+ SEQPULSE_API_KEY = credentials('seqpulse_api_key')
165
+ SEQPULSE_METRICS_ENDPOINT = credentials('seqpulse_metrics_endpoint')
166
+ SEQPULSE_DEPLOYMENT_ID = ''
167
+ }
168
+
169
+ stages {
170
+ stage('Install') {
171
+ steps {
172
+ sh 'npm ci'
173
+ }
174
+ }
175
+
176
+ stage('SeqPulse Trigger') {
177
+ steps {
178
+ script {
179
+ def branch = env.CHANGE_BRANCH ?: env.BRANCH_NAME ?: env.GIT_BRANCH ?: 'main'
180
+ env.SEQPULSE_DEPLOYMENT_ID = sh(
181
+ script: """
182
+ npx -y @nassir_gouomba/seqpulse@0.5.0 ci trigger \
183
+ --env prod \
184
+ --branch "${branch}" \
185
+ --non-blocking true \
186
+ --output deploymentId
187
+ """,
188
+ returnStdout: true
189
+ ).trim()
190
+ }
191
+ }
192
+ }
193
+
194
+ stage('Deploy') {
195
+ steps {
196
+ sh './deploy.sh'
197
+ }
198
+ }
199
+ }
200
+
201
+ post {
202
+ always {
203
+ script {
204
+ def jobStatus = (currentBuild.currentResult ?: 'SUCCESS').toLowerCase()
205
+ sh """
206
+ npx -y @nassir_gouomba/seqpulse@0.5.0 ci finish \
207
+ --deployment-id "${env.SEQPULSE_DEPLOYMENT_ID ?: ''}" \
208
+ --job-status "${jobStatus}" \
209
+ --non-blocking true
210
+ """
211
+ }
212
+ }
213
+ }
214
+ }
215
+ ```
216
+
217
+ ## Notes pratiques
218
+
219
+ - Si le package est deja installe dans le projet, vous pouvez remplacer `npx -y @nassir_gouomba/seqpulse@0.5.0` par `npx seqpulse`.
220
+ - Pour les deploys `prod`, ajoutez un gate explicite sur `main`/tag si votre pipeline est multi-branches.
221
+ - Le pattern recommande est toujours le meme: `trigger -> deploy -> finish`.
package/README.md CHANGED
@@ -8,16 +8,16 @@ SeqPulse Node SDK couvre deux usages:
8
8
  ## Install
9
9
 
10
10
  ```bash
11
- npm install seqpulse
11
+ npm install @nassir_gouomba/seqpulse
12
12
  # or
13
- pnpm add seqpulse
13
+ pnpm add @nassir_gouomba/seqpulse
14
14
  ```
15
15
 
16
16
  ## Runtime (Express)
17
17
 
18
18
  ```js
19
19
  const express = require("express");
20
- const seqpulse = require("seqpulse");
20
+ const seqpulse = require("@nassir_gouomba/seqpulse");
21
21
 
22
22
  const app = express();
23
23
 
@@ -53,7 +53,7 @@ app.listen(3000, () => {
53
53
  ## CI/CD client (trigger/finish)
54
54
 
55
55
  ```js
56
- const seqpulse = require("seqpulse");
56
+ const seqpulse = require("@nassir_gouomba/seqpulse");
57
57
 
58
58
  const client = seqpulse.createCIClient({
59
59
  baseUrl: process.env.SEQPULSE_BASE_URL,
@@ -85,22 +85,27 @@ async function runDeployment() {
85
85
 
86
86
  ```bash
87
87
  # Trigger
88
- npx -y seqpulse@0.4.0 ci trigger \
88
+ DEPLOYMENT_ID="$(npx -y @nassir_gouomba/seqpulse@0.5.0 ci trigger \
89
89
  --env prod \
90
- --github-output "$GITHUB_OUTPUT"
90
+ --output deploymentId)"
91
91
 
92
92
  # Finish
93
- npx -y seqpulse@0.4.0 ci finish \
94
- --deployment-id "$SEQPULSE_DEPLOYMENT_ID" \
93
+ npx -y @nassir_gouomba/seqpulse@0.5.0 ci finish \
94
+ --deployment-id "$DEPLOYMENT_ID" \
95
95
  --job-status "$JOB_STATUS"
96
96
  ```
97
97
 
98
98
  Notes:
99
99
 
100
+ - `--output deploymentId` permet de capturer directement l'identifiant de deployment.
100
101
  - `--github-output` ecrit `deployment_id`, `status`, `http_status`.
101
102
  - mode par defaut: non-bloquant (`--non-blocking true`).
102
103
  - pour mode strict: `--blocking`.
103
104
 
105
+ ## Documentation
106
+
107
+ - [Multi-platform CI/CD snippets](./CI_CD_SNIPPETS_MULTI-PLATFORM.md)
108
+
104
109
  ## Compatibility note
105
110
 
106
111
  Cette evolution **n'ecrase pas** le SDK runtime actuel:
package/bin/seqpulse.js CHANGED
@@ -21,6 +21,7 @@ Common options:
21
21
  --env <name> (default: prod)
22
22
  --non-blocking <true|false> (default: true)
23
23
  --blocking (equivalent to --non-blocking false)
24
+ --output <field> (default: json)
24
25
  --github-output <path> (writes outputs for GitHub Actions)
25
26
 
26
27
  Trigger options:
@@ -97,6 +98,42 @@ function appendGithubOutput(filePath, pairs) {
97
98
  fs.appendFileSync(filePath, `${lines}\n`);
98
99
  }
99
100
 
101
+ function resolveOutputValue(result, output) {
102
+ const mode = String(output || "json").trim();
103
+ if (!mode || mode === "json") {
104
+ return JSON.stringify(result);
105
+ }
106
+
107
+ const aliases = {
108
+ deployment_id: "deploymentId",
109
+ http_status: "httpStatus",
110
+ };
111
+ const path = (aliases[mode] || mode).split(".");
112
+
113
+ let current = result;
114
+ for (const segment of path) {
115
+ if (current === undefined || current === null) {
116
+ current = "";
117
+ break;
118
+ }
119
+ current = current[segment];
120
+ }
121
+
122
+ if (current === undefined || current === null) {
123
+ return "";
124
+ }
125
+
126
+ if (typeof current === "object") {
127
+ return JSON.stringify(current);
128
+ }
129
+
130
+ return String(current);
131
+ }
132
+
133
+ function printResult(result, output) {
134
+ console.log(sanitizeOutput(resolveOutputValue(result, output)));
135
+ }
136
+
100
137
  function resolveNonBlocking(options) {
101
138
  if (options.blocking !== undefined) return false;
102
139
  if (options["non-blocking"] !== undefined) return parseBoolean(options["non-blocking"], true);
@@ -130,7 +167,7 @@ async function runTrigger(options) {
130
167
  http_status: result.httpStatus || "",
131
168
  });
132
169
 
133
- console.log(JSON.stringify({ action: "trigger", ...result }));
170
+ printResult({ action: "trigger", ...result }, options.output);
134
171
 
135
172
  if (!result.ok && !clientConfig.nonBlocking) {
136
173
  process.exitCode = 1;
@@ -140,7 +177,12 @@ async function runTrigger(options) {
140
177
  async function runFinish(options) {
141
178
  const clientConfig = buildClient(options);
142
179
  const deploymentId = options["deployment-id"] || process.env.SEQPULSE_DEPLOYMENT_ID || "";
143
- const jobStatus = options["job-status"] || process.env.JOB_STATUS || process.env.CI_JOB_STATUS || "success";
180
+ const jobStatus =
181
+ options["job-status"] ||
182
+ process.env.JOB_STATUS ||
183
+ process.env.CI_JOB_STATUS ||
184
+ process.env.BUILD_RESULT ||
185
+ "success";
144
186
  const resultValue = options.result || seqpulse.inferResultFromPipelineStatus(jobStatus);
145
187
 
146
188
  const client = seqpulse.createCIClient(clientConfig);
@@ -154,7 +196,7 @@ async function runFinish(options) {
154
196
  http_status: result.httpStatus || "",
155
197
  });
156
198
 
157
- console.log(JSON.stringify({ action: "finish", ...result }));
199
+ printResult({ action: "finish", ...result }, options.output);
158
200
 
159
201
  if (!result.ok && !clientConfig.nonBlocking) {
160
202
  process.exitCode = 1;
package/index.js CHANGED
@@ -228,9 +228,11 @@ function buildCiIdempotencyKey() {
228
228
 
229
229
  function inferBranchName() {
230
230
  return (
231
+ process.env.CHANGE_BRANCH ||
231
232
  process.env.GITHUB_REF_NAME ||
232
233
  process.env.CI_COMMIT_REF_NAME ||
233
234
  process.env.CIRCLE_BRANCH ||
235
+ process.env.GIT_BRANCH ||
234
236
  process.env.BRANCH_NAME ||
235
237
  "unknown"
236
238
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seqpulse",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "SeqPulse SDK for metrics endpoint instrumentation and HMAC validation",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -18,6 +18,7 @@
18
18
  "index.d.ts",
19
19
  "bin/seqpulse.js",
20
20
  "README.md",
21
+ "CI_CD_SNIPPETS_MULTI-PLATFORM.md",
21
22
  "LICENSE",
22
23
  "scripts/smoke.js"
23
24
  ],