@orderly.network/npm-release 0.0.2-alpha.5

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.
package/.gitlab-ci.yml ADDED
@@ -0,0 +1,4 @@
1
+ include:
2
+ - project: "orderlynetwork/orderly-fe/js-sdks/common-ci"
3
+ ref: main
4
+ file: "/npm-release.yml"
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # @orderly.network/npm-release
2
+
3
+ CLI for releasing npm packages using [release-it](https://github.com/release-it/release-it), with support for environment-based registry/token config, Git auth, pre-release tags, and Slack notifications.
4
+
5
+ ## Usage
6
+
7
+ From your project root:
8
+
9
+ ```bash
10
+ npx @orderly.network/npm-release
11
+ ```
12
+
13
+ Or add as a devDependency and run via scripts:
14
+
15
+ ```bash
16
+ pnpm add -D @orderly.network/npm-release
17
+ ```
18
+
19
+ ```json
20
+ {
21
+ "scripts": {
22
+ "release": "orderly-npm-release",
23
+ "release:patch": "RELEASE_VERSION_TYPE=patch orderly-npm-release",
24
+ "release:minor": "RELEASE_VERSION_TYPE=minor orderly-npm-release",
25
+ "release:major": "RELEASE_VERSION_TYPE=major orderly-npm-release"
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## Environment variables
31
+
32
+ | Variable | Description |
33
+ | ---------------------- | ------------------------------------------------------------------------------------- |
34
+ | `NPM_REGISTRY` | npm registry URL (default: `https://registry.npmjs.org`) |
35
+ | `NPM_TOKEN` | Auth token for publishing; written to `.npmrc` when set |
36
+ | `GIT_TOKEN` | Git personal access token for push (e.g. GitLab) |
37
+ | `GIT_USERNAME` | Git username (used with token for authenticated remote URL) |
38
+ | `GIT_NAME` | Git `user.name` for commits |
39
+ | `GIT_EMAIL` | Git `user.email` for commits |
40
+ | `GIT_COMMIT_MESSAGE` | Optional custom commit message |
41
+ | `RELEASE_VERSION_TYPE` | Bump type: `major`, `minor`, or `patch` |
42
+ | `CUSTOM_PRE_TAG` | Pre-release identifier (e.g. `alpha`, `beta`); enables `--preRelease` and `--npm.tag` |
43
+ | `SLACK_WEBHOOK_URL` | Webhook URL for success/failure Slack notifications |
44
+
45
+ ## Prerequisites
46
+
47
+ - Your project must have a `package.json` with a valid `version`.
48
+ - For publishing to npm, configure `.release-it.json` in your project (or rely on defaults). This package ships a default [.release-it.json](.release-it.json) you can copy or merge.
package/index.mjs ADDED
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { $ } from "zx";
5
+ import releaseIt from "release-it";
6
+
7
+ $.verbose = true;
8
+
9
+ const npm = {
10
+ registry: process.env.NPM_REGISTRY,
11
+ token: process.env.NPM_TOKEN,
12
+ };
13
+
14
+ const git = {
15
+ token: process.env.GIT_TOKEN,
16
+ username: process.env.GIT_USERNAME,
17
+ name: process.env.GIT_NAME,
18
+ email: process.env.GIT_EMAIL,
19
+ commitMessage: process.env.GIT_COMMIT_MESSAGE,
20
+ };
21
+
22
+ const customPreTag = process.env.CUSTOM_PRE_TAG;
23
+
24
+ // Custom release version type (major, minor, patch)
25
+ const releaseVersionType = process.env.RELEASE_VERSION_TYPE;
26
+
27
+ /** Inlined config (formerly .release-it.json) */
28
+ const RELEASE_IT_CONFIG = {
29
+ ci: true,
30
+ git: {
31
+ commit: true,
32
+ tag: true,
33
+ push: true,
34
+ // Allow release when working dir is not clean so it works as a third-party package in CI
35
+ // (e.g. after npm install or build steps that touch lockfile or generated files).
36
+ requireCleanWorkingDir: false,
37
+ },
38
+ npm: {
39
+ publish: true,
40
+ // Skip npm collaborator/registry checks so publishing works when used as a third-party
41
+ // package or with private registries that don't support whoami/access (actual publish
42
+ // still fails if the user lacks permission).
43
+ skipChecks: true,
44
+ },
45
+ github: {
46
+ release: false,
47
+ },
48
+ };
49
+ const slackWebhookUrl = process.env.SLACK_WEBHOOK_URL;
50
+
51
+ function parseVersion(version) {
52
+ const m = /^(\d+\.\d+\.\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(version);
53
+ if (!m) return { base: version, isPrerelease: false, preId: "" };
54
+ const base = m[1];
55
+ const pre = m[2] || "";
56
+ const preId = pre ? pre.split(".")[0] : "";
57
+ return { base, isPrerelease: Boolean(pre), preId };
58
+ }
59
+
60
+ function readPackageJson() {
61
+ const pkgPath = path.join(process.cwd(), "package.json");
62
+ return JSON.parse(fs.readFileSync(pkgPath, "utf8"));
63
+ }
64
+
65
+ function readPackageVersion() {
66
+ const pkg = readPackageJson();
67
+ return String(pkg.version || "");
68
+ }
69
+
70
+ /**
71
+ * Send Slack notification via webhook.
72
+ * Called on both success and failure so CI/user gets notified either way.
73
+ * @param {object} opts
74
+ * @param {boolean} opts.success - whether release succeeded
75
+ * @param {string} [opts.version] - package version (after release on success)
76
+ * @param {string} [opts.error] - error message on failure
77
+ */
78
+
79
+ /**
80
+ * Build package page URL for public or private npm registry.
81
+ * Public (no NPM_REGISTRY or registry.npmjs.org): https://www.npmjs.com/package/<name>
82
+ * Private: <registry>/-/web/detail/<name> (Verdaccio-style)
83
+ */
84
+ function getPackagePageUrl(pkgName) {
85
+ const raw = npm.registry || "https://registry.npmjs.org";
86
+ const registry = raw.replace(/\/$/, "");
87
+ const isPublic = !npm.registry || registry === "https://registry.npmjs.org";
88
+ if (isPublic) {
89
+ return `https://www.npmjs.com/package/${encodeURIComponent(pkgName)}`;
90
+ }
91
+ return `${registry}/-/web/detail/${encodeURIComponent(pkgName)}`;
92
+ }
93
+
94
+ async function sendSlackNotify({ success, error }) {
95
+ if (!slackWebhookUrl) return;
96
+
97
+ const { name: pkgName, version } = readPackageJson();
98
+ const packageUrl = getPackagePageUrl(pkgName);
99
+ const linkedPkg = `<${packageUrl}|${pkgName}@${version}>`;
100
+ const text = success
101
+ ? `packages published successfully:\n${linkedPkg}`
102
+ : `packages publish failed:\n${linkedPkg}\n${error || "Unknown error"}`;
103
+
104
+ try {
105
+ const res = await fetch(slackWebhookUrl, {
106
+ method: "POST",
107
+ headers: { "Content-Type": "application/json" },
108
+ body: JSON.stringify({ text, mrkdwn: true }),
109
+ });
110
+ if (!res.ok) {
111
+ console.warn(
112
+ "[release] Slack notify failed:",
113
+ res.status,
114
+ await res.text()
115
+ );
116
+ }
117
+ } catch (e) {
118
+ console.warn("[release] Slack notify error:", e.message);
119
+ }
120
+ }
121
+
122
+ function sanitizePreId(id) {
123
+ return String(id).replaceAll("/", "-");
124
+ }
125
+
126
+ /**
127
+ * Extract the repository path (owner/name) from the git remote origin URL.
128
+ * Supports HTTPS and SSH URLs for GitHub and GitLab.
129
+ * Examples:
130
+ * https://github.com/OrderlyNetwork/orderly-sdk-js.git => OrderlyNetwork/orderly-sdk-js
131
+ * git@github.com:OrderlyNetwork/orderly-sdk-js.git => OrderlyNetwork/orderly-sdk-js
132
+ */
133
+ async function getRepoPath() {
134
+ const res = await $`git remote get-url origin`;
135
+ // console.log("getRepoPath: ", res);
136
+ const origin = res.stdout?.replace(/\s+/g, "");
137
+ const regex = /(?:github\.com|gitlab\.com)[:/](.+?\/.+?)\.git/;
138
+ const match = origin.match(regex);
139
+ const repoPath = match ? match[1] : null;
140
+ return repoPath;
141
+ }
142
+
143
+ /**
144
+ * Construct the remote git repository URL with authentication token if provided.
145
+ * Supports GitLab personal access token authentication format.
146
+ */
147
+ async function getRemoteUrlWithToken() {
148
+ const repoPath = await getRepoPath();
149
+
150
+ if (git.token && git.username && repoPath) {
151
+ // Format: https://<username>:<token>@gitlab.com/<repoPath>.git
152
+ return `https://${git.username}:${git.token}@gitlab.com/${repoPath}.git`;
153
+ }
154
+
155
+ return "";
156
+ }
157
+
158
+ async function configureGit() {
159
+ if (git.name) await $`git config user.name ${git.name}`;
160
+ if (git.email) await $`git config user.email ${git.email}`;
161
+
162
+ const authedRemote = await getRemoteUrlWithToken();
163
+ if (authedRemote) {
164
+ await $`git remote set-url origin ${authedRemote}`;
165
+ }
166
+ }
167
+
168
+ function configureNpmEnv() {
169
+ // Prefer environment-driven registry (matches previous behavior: npm_config_registry).
170
+ if (npm.registry) {
171
+ process.env.npm_config_registry = npm.registry;
172
+ }
173
+
174
+ if (npm.token) {
175
+ process.env.NPM_TOKEN = npm.token;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Authenticate npm by appending an auth token to the local ~/.npmrc file.
181
+ * Uses custom registry if provided, defaults to public npm registry.
182
+ */
183
+ async function authNPM() {
184
+ // Remove protocol from registry URL for .npmrc syntax
185
+ const registry = (npm.registry || "https://registry.npmjs.org")
186
+ .replace("http://", "")
187
+ .replace("https://", "");
188
+ const content = `\n//${registry}/:_authToken="${npm.token}"`;
189
+ await $`echo ${content} >> .npmrc`;
190
+ }
191
+
192
+ /**
193
+ * When current version is already a pre-release (e.g. 1.0.0-alpha.0) and CUSTOM_PRE_TAG
194
+ * matches the same preId (e.g. "alpha"), use increment "prerelease" so release-it bumps
195
+ * to 1.0.0-alpha.1. Otherwise use RELEASE_VERSION_TYPE (patch/minor/major).
196
+ * Returns options for release-it programmatic API (merged with RELEASE_IT_CONFIG).
197
+ */
198
+ async function getReleaseItOptions() {
199
+ let increment = releaseVersionType;
200
+
201
+ if (customPreTag) {
202
+ const currentVersion = readPackageVersion();
203
+ const { isPrerelease, preId } = parseVersion(currentVersion);
204
+ const normalizedPreTag = sanitizePreId(customPreTag);
205
+ // Continue pre-release: alpha.0 -> alpha.1 (same preId)
206
+ if (isPrerelease && preId === normalizedPreTag) {
207
+ increment = "prerelease";
208
+ }
209
+ }
210
+
211
+ const options = {
212
+ ...RELEASE_IT_CONFIG,
213
+ increment,
214
+ };
215
+
216
+ if (customPreTag) {
217
+ options.preRelease = customPreTag;
218
+ options.npm.tag = customPreTag;
219
+ }
220
+
221
+ return options;
222
+ }
223
+
224
+ async function main() {
225
+ try {
226
+ // Authenticate with npm registry if token provided
227
+ if (npm.token) {
228
+ await authNPM();
229
+ }
230
+
231
+ configureNpmEnv();
232
+ await configureGit();
233
+
234
+ const releaseItOptions = await getReleaseItOptions();
235
+ await releaseIt(releaseItOptions);
236
+
237
+ await sendSlackNotify({ success: true });
238
+ } catch (err) {
239
+ await sendSlackNotify({
240
+ success: false,
241
+ error: err?.message,
242
+ });
243
+ throw err;
244
+ }
245
+ }
246
+
247
+ main();
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@orderly.network/npm-release",
3
+ "version": "0.0.2-alpha.5",
4
+ "main": "index.mjs",
5
+ "module": "index.mjs",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "orderly-npm-release": "./index.mjs"
9
+ },
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "scripts": {
14
+ "release": "node index.mjs"
15
+ },
16
+ "dependencies": {
17
+ "release-it": "^19.2.4",
18
+ "zx": "^8.8.5"
19
+ }
20
+ }