seqpulse 0.4.0 → 0.5.2

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 `seqpulse@0.5.1` 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 seqpulse@0.5.1 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 seqpulse@0.5.1 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 seqpulse@0.5.1 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 seqpulse@0.5.1 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 seqpulse@0.5.1 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 seqpulse@0.5.1 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 seqpulse@0.5.1 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 seqpulse@0.5.1 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 seqpulse@0.5.1` 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
@@ -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 seqpulse@0.5.1 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 seqpulse@0.5.1 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
@@ -4,6 +4,8 @@
4
4
  const fs = require("node:fs");
5
5
  const seqpulse = require("../index.js");
6
6
 
7
+ const BOOLEAN_FLAGS = new Set(["blocking", "help", "h"]);
8
+
7
9
  function printUsage() {
8
10
  console.error(`Usage:
9
11
  seqpulse ci trigger [options]
@@ -21,6 +23,7 @@ Common options:
21
23
  --env <name> (default: prod)
22
24
  --non-blocking <true|false> (default: true)
23
25
  --blocking (equivalent to --non-blocking false)
26
+ --output <field> (default: json)
24
27
  --github-output <path> (writes outputs for GitHub Actions)
25
28
 
26
29
  Trigger options:
@@ -56,6 +59,9 @@ function parseArgs(argv) {
56
59
  const key = token.slice(2);
57
60
  const next = argv[i + 1];
58
61
  if (!next || next.startsWith("--")) {
62
+ if (!BOOLEAN_FLAGS.has(key)) {
63
+ throw new Error(`Option --${key} requires a value`);
64
+ }
59
65
  options[key] = true;
60
66
  continue;
61
67
  }
@@ -97,6 +103,42 @@ function appendGithubOutput(filePath, pairs) {
97
103
  fs.appendFileSync(filePath, `${lines}\n`);
98
104
  }
99
105
 
106
+ function resolveOutputValue(result, output) {
107
+ const mode = String(output || "json").trim();
108
+ if (!mode || mode === "json") {
109
+ return JSON.stringify(result);
110
+ }
111
+
112
+ const aliases = {
113
+ deployment_id: "deploymentId",
114
+ http_status: "httpStatus",
115
+ };
116
+ const path = (aliases[mode] || mode).split(".");
117
+
118
+ let current = result;
119
+ for (const segment of path) {
120
+ if (current === undefined || current === null) {
121
+ current = "";
122
+ break;
123
+ }
124
+ current = current[segment];
125
+ }
126
+
127
+ if (current === undefined || current === null) {
128
+ return "";
129
+ }
130
+
131
+ if (typeof current === "object") {
132
+ return JSON.stringify(current);
133
+ }
134
+
135
+ return String(current);
136
+ }
137
+
138
+ function printResult(result, output) {
139
+ console.log(sanitizeOutput(resolveOutputValue(result, output)));
140
+ }
141
+
100
142
  function resolveNonBlocking(options) {
101
143
  if (options.blocking !== undefined) return false;
102
144
  if (options["non-blocking"] !== undefined) return parseBoolean(options["non-blocking"], true);
@@ -130,7 +172,7 @@ async function runTrigger(options) {
130
172
  http_status: result.httpStatus || "",
131
173
  });
132
174
 
133
- console.log(JSON.stringify({ action: "trigger", ...result }));
175
+ printResult({ action: "trigger", ...result }, options.output);
134
176
 
135
177
  if (!result.ok && !clientConfig.nonBlocking) {
136
178
  process.exitCode = 1;
@@ -140,7 +182,12 @@ async function runTrigger(options) {
140
182
  async function runFinish(options) {
141
183
  const clientConfig = buildClient(options);
142
184
  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";
185
+ const jobStatus =
186
+ options["job-status"] ||
187
+ process.env.JOB_STATUS ||
188
+ process.env.CI_JOB_STATUS ||
189
+ process.env.BUILD_RESULT ||
190
+ "success";
144
191
  const resultValue = options.result || seqpulse.inferResultFromPipelineStatus(jobStatus);
145
192
 
146
193
  const client = seqpulse.createCIClient(clientConfig);
@@ -154,7 +201,7 @@ async function runFinish(options) {
154
201
  http_status: result.httpStatus || "",
155
202
  });
156
203
 
157
- console.log(JSON.stringify({ action: "finish", ...result }));
204
+ printResult({ action: "finish", ...result }, options.output);
158
205
 
159
206
  if (!result.ok && !clientConfig.nonBlocking) {
160
207
  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.2",
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
  ],