@kaikybrofc/omnizap-system 2.1.9 → 2.2.0
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/.env.example +31 -0
- package/README.md +26 -2
- package/package.json +1 -1
- package/scripts/github-release-notify.mjs +188 -0
- package/scripts/release.sh +264 -4
package/.env.example
CHANGED
|
@@ -521,6 +521,13 @@ DEPLOY_PACKAGE_SECONDARY_TOKEN_KEYS=
|
|
|
521
521
|
# ==============================
|
|
522
522
|
# Release (auto commit/push)
|
|
523
523
|
# ==============================
|
|
524
|
+
# Tipo de bump padrão no npm run release (patch/minor/major...)
|
|
525
|
+
RELEASE_TYPE=patch
|
|
526
|
+
# Opcional: força versão exata (ex: 2.2.0), ignorando RELEASE_TYPE
|
|
527
|
+
RELEASE_FORCE_VERSION=
|
|
528
|
+
# Rollover automático de patch: quando patch >= RELEASE_PATCH_ROLLOVER_AT, vira (major).(minor+1).0
|
|
529
|
+
RELEASE_PATCH_ROLLOVER_ENABLED=1
|
|
530
|
+
RELEASE_PATCH_ROLLOVER_AT=10
|
|
524
531
|
# Faz commit automatico de alteracoes pendentes antes do release
|
|
525
532
|
RELEASE_GIT_AUTO_COMMIT=1
|
|
526
533
|
# Faz push automatico dos commits gerados no release
|
|
@@ -532,3 +539,27 @@ RELEASE_GIT_BRANCH=
|
|
|
532
539
|
RELEASE_GIT_PRE_COMMIT_MESSAGE=chore(release): auto-commit before release
|
|
533
540
|
RELEASE_GIT_COMMIT_VERSION=1
|
|
534
541
|
RELEASE_GIT_VERSION_COMMIT_PREFIX=chore(release): v
|
|
542
|
+
|
|
543
|
+
# Cria/atualiza GitHub Release (aba Releases) automaticamente no npm run release
|
|
544
|
+
RELEASE_GITHUB_RELEASE=1
|
|
545
|
+
# Se 1, falha o release caso GitHub Release esteja desativado
|
|
546
|
+
RELEASE_REQUIRE_GITHUB_RELEASE=1
|
|
547
|
+
RELEASE_GITHUB_REPO=kaikybrofc/omnizap-system
|
|
548
|
+
RELEASE_GITHUB_TOKEN=
|
|
549
|
+
RELEASE_GITHUB_TAG_PREFIX=v
|
|
550
|
+
RELEASE_GITHUB_NAME_PREFIX=v
|
|
551
|
+
RELEASE_GITHUB_GENERATE_NOTES=1
|
|
552
|
+
# Opcional: 1 para prerelease, 0 para release normal, vazio = auto (detecta '-' na versao)
|
|
553
|
+
RELEASE_GITHUB_PRERELEASE=
|
|
554
|
+
RELEASE_GITHUB_DRAFT=0
|
|
555
|
+
# Opcional: commit/tag alvo (vazio usa HEAD atual)
|
|
556
|
+
RELEASE_GITHUB_TARGET=
|
|
557
|
+
|
|
558
|
+
# Se 1, exige publish em ambos os registries no release (GitHub Packages + npmjs)
|
|
559
|
+
RELEASE_REQUIRE_DUAL_PUBLISH=1
|
|
560
|
+
# Verificação final: local + registries + GitHub Release na mesma versão
|
|
561
|
+
RELEASE_VERIFY_UNIFIED_VERSION=1
|
|
562
|
+
RELEASE_VERIFY_PRIMARY_REGISTRY=https://npm.pkg.github.com
|
|
563
|
+
RELEASE_VERIFY_SECONDARY_REGISTRY=https://registry.npmjs.org
|
|
564
|
+
RELEASE_VERIFY_PRIMARY_TOKEN_KEYS=DEPLOY_PACKAGE_TOKEN,DEPLOY_GITHUB_TOKEN,GITHUB_TOKEN,GH_TOKEN,NPM_TOKEN,NODE_AUTH_TOKEN
|
|
565
|
+
RELEASE_VERIFY_SECONDARY_TOKEN_KEYS=DEPLOY_PACKAGE_SECONDARY_TOKEN,NPM_TOKEN,NODE_AUTH_TOKEN
|
package/README.md
CHANGED
|
@@ -132,7 +132,7 @@ Variáveis legadas foram mantidas por compatibilidade (`QUOTE_API_URL`, `WAIFU_A
|
|
|
132
132
|
- `npm run pm2:prod`: sobe com PM2 usando `ecosystem.prod.config.cjs`.
|
|
133
133
|
- `npm run deploy`: deploy automático de `public/` com cache-bust, backup, validação e reload do Nginx.
|
|
134
134
|
- `npm run deploy:dry-run`: simula o deploy sem publicar/recarregar serviços.
|
|
135
|
-
- `npm run release`:
|
|
135
|
+
- `npm run release`: release completo com versão unificada (npmjs + GitHub Packages + GitHub Release) e verificação final.
|
|
136
136
|
- `npm run release:minor`: bump `minor` + deploy + publish do package.
|
|
137
137
|
- `npm run release:major`: bump `major` + deploy + publish do package.
|
|
138
138
|
- `npm run test`: executa testes Node (`node --test`).
|
|
@@ -224,10 +224,14 @@ Comando único de release (patch + deploy + publish):
|
|
|
224
224
|
npm run release
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
-
`npm run release`
|
|
227
|
+
`npm run release` executa publish primário + secundário por padrão e valida consistência final de versão.
|
|
228
228
|
|
|
229
229
|
Variáveis do fluxo de release (git):
|
|
230
230
|
|
|
231
|
+
- `RELEASE_TYPE` (default: `patch`)
|
|
232
|
+
- `RELEASE_FORCE_VERSION` (opcional) - força versão exata (ex.: `2.2.0`)
|
|
233
|
+
- `RELEASE_PATCH_ROLLOVER_ENABLED` (default: `1`) - rollover automático de patch
|
|
234
|
+
- `RELEASE_PATCH_ROLLOVER_AT` (default: `10`) - quando patch atingir este valor, próximo release vira `major.(minor+1).0`
|
|
231
235
|
- `RELEASE_GIT_AUTO_COMMIT` (default: `1`) - commit automático se houver alterações pendentes
|
|
232
236
|
- `RELEASE_GIT_AUTO_PUSH` (default: `1`) - push automático dos commits gerados
|
|
233
237
|
- `RELEASE_GIT_REMOTE` (default: `origin`)
|
|
@@ -235,6 +239,26 @@ Variáveis do fluxo de release (git):
|
|
|
235
239
|
- `RELEASE_GIT_PRE_COMMIT_MESSAGE` (default: `chore(release): auto-commit before release`)
|
|
236
240
|
- `RELEASE_GIT_COMMIT_VERSION` (default: `1`) - commita alteração da versão após sucesso
|
|
237
241
|
- `RELEASE_GIT_VERSION_COMMIT_PREFIX` (default: `chore(release): v`)
|
|
242
|
+
- `RELEASE_GITHUB_RELEASE` (default: `1`) - cria/atualiza GitHub Release na aba Releases
|
|
243
|
+
- `RELEASE_REQUIRE_GITHUB_RELEASE` (default: `1`) - falha se GitHub Release estiver desativado
|
|
244
|
+
- `RELEASE_GITHUB_REPO` (opcional; ex.: `kaikybrofc/omnizap-system`)
|
|
245
|
+
- `RELEASE_GITHUB_TOKEN` (opcional; fallback: `DEPLOY_GITHUB_TOKEN`/`GITHUB_TOKEN`/`GH_TOKEN`)
|
|
246
|
+
- `RELEASE_GITHUB_TAG_PREFIX` (default: `v`) - prefixo da tag (`v2.1.9`)
|
|
247
|
+
- `RELEASE_GITHUB_NAME_PREFIX` (default: `v`) - prefixo do nome exibido na release
|
|
248
|
+
- `RELEASE_GITHUB_GENERATE_NOTES` (default: `1`) - usa notas automáticas do GitHub
|
|
249
|
+
- `RELEASE_GITHUB_PRERELEASE` (default: auto) - vazio detecta `-` na versão como prerelease
|
|
250
|
+
- `RELEASE_GITHUB_DRAFT` (default: `0`)
|
|
251
|
+
- `RELEASE_GITHUB_TARGET` (opcional; vazio usa `HEAD`)
|
|
252
|
+
- `RELEASE_REQUIRE_DUAL_PUBLISH` (default: `1`) - exige publish em GitHub Packages e npmjs
|
|
253
|
+
- `RELEASE_VERIFY_UNIFIED_VERSION` (default: `1`) - valida versão final em local + registries + GitHub Release
|
|
254
|
+
- `RELEASE_VERIFY_PRIMARY_REGISTRY` (default: `https://npm.pkg.github.com`)
|
|
255
|
+
- `RELEASE_VERIFY_SECONDARY_REGISTRY` (default: `https://registry.npmjs.org`)
|
|
256
|
+
- `RELEASE_VERIFY_PRIMARY_TOKEN_KEYS` / `RELEASE_VERIFY_SECONDARY_TOKEN_KEYS` - ordem de fallback de tokens para verificação
|
|
257
|
+
|
|
258
|
+
Exemplo de rollover automático:
|
|
259
|
+
|
|
260
|
+
- `2.1.9` + `npm run release` -> `2.1.10`
|
|
261
|
+
- `2.1.10` + `npm run release` -> `2.2.0`
|
|
238
262
|
|
|
239
263
|
## Execução com PM2
|
|
240
264
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import dotenv from 'dotenv';
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
const projectRoot = path.resolve(__dirname, '..');
|
|
12
|
+
|
|
13
|
+
dotenv.config({ path: path.join(projectRoot, '.env') });
|
|
14
|
+
|
|
15
|
+
const args = process.argv.slice(2);
|
|
16
|
+
const action = String(args[0] || '').trim();
|
|
17
|
+
|
|
18
|
+
const getArg = (flag, fallback = '') => {
|
|
19
|
+
const index = args.indexOf(flag);
|
|
20
|
+
if (index === -1) return fallback;
|
|
21
|
+
return String(args[index + 1] || fallback).trim();
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const env = (...keys) => {
|
|
25
|
+
for (const key of keys) {
|
|
26
|
+
const value = process.env[key];
|
|
27
|
+
if (value && String(value).trim()) return String(value).trim();
|
|
28
|
+
}
|
|
29
|
+
return '';
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const toBool = (value, fallback = false) => {
|
|
33
|
+
if (value === undefined || value === null || value === '') return fallback;
|
|
34
|
+
const normalized = String(value).trim().toLowerCase();
|
|
35
|
+
return ['1', 'true', 'yes', 'on'].includes(normalized);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const parseRepoFromRemote = () => {
|
|
39
|
+
try {
|
|
40
|
+
const remoteUrl = execSync('git config --get remote.origin.url', {
|
|
41
|
+
cwd: projectRoot,
|
|
42
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
43
|
+
})
|
|
44
|
+
.toString('utf8')
|
|
45
|
+
.trim();
|
|
46
|
+
if (!remoteUrl) return '';
|
|
47
|
+
|
|
48
|
+
const httpsMatch = remoteUrl.match(/github\.com\/([^/]+\/[^/.]+)(?:\.git)?$/i);
|
|
49
|
+
if (httpsMatch?.[1]) return httpsMatch[1];
|
|
50
|
+
|
|
51
|
+
const sshMatch = remoteUrl.match(/github\.com:([^/]+\/[^/.]+)(?:\.git)?$/i);
|
|
52
|
+
if (sshMatch?.[1]) return sshMatch[1];
|
|
53
|
+
} catch {
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
return '';
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const token = env('RELEASE_GITHUB_TOKEN', 'DEPLOY_GITHUB_TOKEN', 'GITHUB_TOKEN', 'GH_TOKEN');
|
|
60
|
+
const repository = env('RELEASE_GITHUB_REPO', 'DEPLOY_GITHUB_REPO', 'GITHUB_REPOSITORY') || parseRepoFromRemote();
|
|
61
|
+
|
|
62
|
+
if (!action || !['upsert', 'get'].includes(action)) {
|
|
63
|
+
console.error('Uso: node scripts/github-release-notify.mjs <upsert|get> --tag vX.Y.Z [opções]');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!token || !repository) {
|
|
68
|
+
console.error('GitHub release notify ignorado: token ou repositório não configurado.');
|
|
69
|
+
process.exit(2);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const [repoOwnerRaw, repoNameRaw] = repository.split('/', 2);
|
|
73
|
+
const repoOwner = String(repoOwnerRaw || '').trim();
|
|
74
|
+
const repoName = String(repoNameRaw || '').trim();
|
|
75
|
+
if (!repoOwner || !repoName) {
|
|
76
|
+
console.error('GitHub release notify ignorado: formato de repositório inválido (esperado owner/repo).');
|
|
77
|
+
process.exit(2);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const tag = getArg('--tag');
|
|
81
|
+
const target = getArg('--target');
|
|
82
|
+
const name = getArg('--name', tag);
|
|
83
|
+
const body = getArg('--body', '');
|
|
84
|
+
const generateNotes = toBool(getArg('--generate-notes', 'true'), true);
|
|
85
|
+
const prerelease = toBool(getArg('--prerelease', 'false'), false);
|
|
86
|
+
const draft = toBool(getArg('--draft', 'false'), false);
|
|
87
|
+
|
|
88
|
+
if (!tag) {
|
|
89
|
+
console.error('Parâmetro obrigatório ausente: --tag');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const headers = {
|
|
94
|
+
Accept: 'application/vnd.github+json',
|
|
95
|
+
Authorization: `Bearer ${token}`,
|
|
96
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
97
|
+
'Content-Type': 'application/json',
|
|
98
|
+
'User-Agent': 'omnizap-release-script',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const request = async (url, method, payload) => {
|
|
102
|
+
const response = await fetch(url, {
|
|
103
|
+
method,
|
|
104
|
+
headers,
|
|
105
|
+
body: payload ? JSON.stringify(payload) : undefined,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const raw = await response.text();
|
|
109
|
+
let data = null;
|
|
110
|
+
try {
|
|
111
|
+
data = raw ? JSON.parse(raw) : null;
|
|
112
|
+
} catch {
|
|
113
|
+
data = null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
ok: response.ok,
|
|
118
|
+
status: response.status,
|
|
119
|
+
data,
|
|
120
|
+
raw,
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const failFromResponse = (response, fallbackPrefix = 'GitHub API') => {
|
|
125
|
+
const message = response?.data?.message || response?.raw || 'unknown error';
|
|
126
|
+
throw new Error(`${fallbackPrefix} ${response?.status ?? 'n/a'}: ${message}`);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const run = async () => {
|
|
130
|
+
const baseUrl = `https://api.github.com/repos/${encodeURIComponent(repoOwner)}/${encodeURIComponent(repoName)}`;
|
|
131
|
+
|
|
132
|
+
const byTag = await request(`${baseUrl}/releases/tags/${encodeURIComponent(tag)}`, 'GET');
|
|
133
|
+
let existingRelease = null;
|
|
134
|
+
if (byTag.ok) {
|
|
135
|
+
existingRelease = byTag.data;
|
|
136
|
+
} else if (byTag.status !== 404) {
|
|
137
|
+
failFromResponse(byTag, 'GitHub API');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (action === 'get') {
|
|
141
|
+
if (!existingRelease) {
|
|
142
|
+
throw new Error(`GitHub release não encontrada para tag ${tag}`);
|
|
143
|
+
}
|
|
144
|
+
const url = existingRelease.html_url || '';
|
|
145
|
+
process.stdout.write(`found id=${existingRelease.id} tag=${tag} url=${url}`);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const commonPayload = {
|
|
150
|
+
tag_name: tag,
|
|
151
|
+
target_commitish: target || undefined,
|
|
152
|
+
name: name || tag,
|
|
153
|
+
draft,
|
|
154
|
+
prerelease,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
if (body) {
|
|
158
|
+
commonPayload.body = body;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (existingRelease) {
|
|
162
|
+
const update = await request(`${baseUrl}/releases/${existingRelease.id}`, 'PATCH', commonPayload);
|
|
163
|
+
if (!update.ok) {
|
|
164
|
+
failFromResponse(update, 'GitHub API');
|
|
165
|
+
}
|
|
166
|
+
const url = update.data?.html_url || '';
|
|
167
|
+
process.stdout.write(`updated id=${update.data?.id} tag=${tag} url=${url}`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const createPayload = { ...commonPayload };
|
|
172
|
+
if (generateNotes) {
|
|
173
|
+
createPayload.generate_release_notes = true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const created = await request(`${baseUrl}/releases`, 'POST', createPayload);
|
|
177
|
+
if (!created.ok) {
|
|
178
|
+
failFromResponse(created, 'GitHub API');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const url = created.data?.html_url || '';
|
|
182
|
+
process.stdout.write(`created id=${created.data?.id} tag=${tag} url=${url}`);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
run().catch((error) => {
|
|
186
|
+
console.error(error?.message || error);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
});
|
package/scripts/release.sh
CHANGED
|
@@ -3,6 +3,9 @@ set -euo pipefail
|
|
|
3
3
|
|
|
4
4
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
5
|
RELEASE_TYPE="${RELEASE_TYPE:-patch}"
|
|
6
|
+
RELEASE_FORCE_VERSION="${RELEASE_FORCE_VERSION:-}"
|
|
7
|
+
RELEASE_PATCH_ROLLOVER_ENABLED="${RELEASE_PATCH_ROLLOVER_ENABLED:-1}"
|
|
8
|
+
RELEASE_PATCH_ROLLOVER_AT="${RELEASE_PATCH_ROLLOVER_AT:-10}"
|
|
6
9
|
RELEASE_GIT_AUTO_COMMIT="${RELEASE_GIT_AUTO_COMMIT:-1}"
|
|
7
10
|
RELEASE_GIT_AUTO_PUSH="${RELEASE_GIT_AUTO_PUSH:-1}"
|
|
8
11
|
RELEASE_GIT_REMOTE="${RELEASE_GIT_REMOTE:-origin}"
|
|
@@ -10,6 +13,21 @@ RELEASE_GIT_BRANCH="${RELEASE_GIT_BRANCH:-}"
|
|
|
10
13
|
RELEASE_GIT_PRE_COMMIT_MESSAGE="${RELEASE_GIT_PRE_COMMIT_MESSAGE:-chore(release): auto-commit before release}"
|
|
11
14
|
RELEASE_GIT_COMMIT_VERSION="${RELEASE_GIT_COMMIT_VERSION:-1}"
|
|
12
15
|
RELEASE_GIT_VERSION_COMMIT_PREFIX="${RELEASE_GIT_VERSION_COMMIT_PREFIX:-chore(release): v}"
|
|
16
|
+
RELEASE_GITHUB_RELEASE="${RELEASE_GITHUB_RELEASE:-1}"
|
|
17
|
+
RELEASE_REQUIRE_GITHUB_RELEASE="${RELEASE_REQUIRE_GITHUB_RELEASE:-1}"
|
|
18
|
+
RELEASE_GITHUB_TAG_PREFIX="${RELEASE_GITHUB_TAG_PREFIX:-v}"
|
|
19
|
+
RELEASE_GITHUB_NAME_PREFIX="${RELEASE_GITHUB_NAME_PREFIX:-v}"
|
|
20
|
+
RELEASE_GITHUB_GENERATE_NOTES="${RELEASE_GITHUB_GENERATE_NOTES:-1}"
|
|
21
|
+
RELEASE_GITHUB_PRERELEASE="${RELEASE_GITHUB_PRERELEASE:-}"
|
|
22
|
+
RELEASE_GITHUB_DRAFT="${RELEASE_GITHUB_DRAFT:-0}"
|
|
23
|
+
RELEASE_GITHUB_TARGET="${RELEASE_GITHUB_TARGET:-}"
|
|
24
|
+
RELEASE_REQUIRE_DUAL_PUBLISH="${RELEASE_REQUIRE_DUAL_PUBLISH:-1}"
|
|
25
|
+
RELEASE_VERIFY_UNIFIED_VERSION="${RELEASE_VERIFY_UNIFIED_VERSION:-1}"
|
|
26
|
+
RELEASE_VERIFY_PRIMARY_REGISTRY="${RELEASE_VERIFY_PRIMARY_REGISTRY:-${DEPLOY_PACKAGE_REGISTRY:-https://npm.pkg.github.com}}"
|
|
27
|
+
RELEASE_VERIFY_SECONDARY_REGISTRY="${RELEASE_VERIFY_SECONDARY_REGISTRY:-${DEPLOY_PACKAGE_SECONDARY_REGISTRY:-https://registry.npmjs.org}}"
|
|
28
|
+
RELEASE_VERIFY_PRIMARY_TOKEN_KEYS="${RELEASE_VERIFY_PRIMARY_TOKEN_KEYS:-DEPLOY_PACKAGE_TOKEN,DEPLOY_GITHUB_TOKEN,GITHUB_TOKEN,GH_TOKEN,NPM_TOKEN,NODE_AUTH_TOKEN}"
|
|
29
|
+
RELEASE_VERIFY_SECONDARY_TOKEN_KEYS="${RELEASE_VERIFY_SECONDARY_TOKEN_KEYS:-DEPLOY_PACKAGE_SECONDARY_TOKEN,NPM_TOKEN,NODE_AUTH_TOKEN}"
|
|
30
|
+
TMP_NPMRC_FILES=()
|
|
13
31
|
|
|
14
32
|
case "$RELEASE_TYPE" in
|
|
15
33
|
patch|minor|major|prepatch|preminor|premajor|prerelease)
|
|
@@ -25,6 +43,15 @@ log() {
|
|
|
25
43
|
printf '[release] %s\n' "$*"
|
|
26
44
|
}
|
|
27
45
|
|
|
46
|
+
cleanup_tmp_npmrcs() {
|
|
47
|
+
for npmrc_tmp in "${TMP_NPMRC_FILES[@]:-}"; do
|
|
48
|
+
if [ -n "$npmrc_tmp" ] && [ -f "$npmrc_tmp" ]; then
|
|
49
|
+
rm -f "$npmrc_tmp"
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
}
|
|
53
|
+
trap cleanup_tmp_npmrcs EXIT
|
|
54
|
+
|
|
28
55
|
require_cmd() {
|
|
29
56
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
30
57
|
printf '[release] comando ausente: %s\n' "$1" >&2
|
|
@@ -32,6 +59,23 @@ require_cmd() {
|
|
|
32
59
|
fi
|
|
33
60
|
}
|
|
34
61
|
|
|
62
|
+
to_bool() {
|
|
63
|
+
local value
|
|
64
|
+
value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')"
|
|
65
|
+
case "$value" in
|
|
66
|
+
1|true|yes|on)
|
|
67
|
+
printf 'true'
|
|
68
|
+
;;
|
|
69
|
+
*)
|
|
70
|
+
printf 'false'
|
|
71
|
+
;;
|
|
72
|
+
esac
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
sanitize_npm_output() {
|
|
76
|
+
printf '%s' "$1" | tr -d "\"'[:space:]"
|
|
77
|
+
}
|
|
78
|
+
|
|
35
79
|
resolve_branch() {
|
|
36
80
|
if [ -n "$RELEASE_GIT_BRANCH" ]; then
|
|
37
81
|
printf '%s' "$RELEASE_GIT_BRANCH"
|
|
@@ -49,6 +93,130 @@ resolve_branch() {
|
|
|
49
93
|
printf '%s' "$branch"
|
|
50
94
|
}
|
|
51
95
|
|
|
96
|
+
resolve_token_from_dotenv() {
|
|
97
|
+
local token_keys="$1"
|
|
98
|
+
if [ -z "$token_keys" ]; then
|
|
99
|
+
return 0
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
(
|
|
103
|
+
cd "$PROJECT_ROOT" && TOKEN_KEYS="$token_keys" node --input-type=module -e "
|
|
104
|
+
import dotenv from 'dotenv';
|
|
105
|
+
dotenv.config({ path: '.env' });
|
|
106
|
+
const keys = String(process.env.TOKEN_KEYS || '')
|
|
107
|
+
.split(',')
|
|
108
|
+
.map((item) => item.trim())
|
|
109
|
+
.filter(Boolean);
|
|
110
|
+
for (const key of keys) {
|
|
111
|
+
const value = process.env[key];
|
|
112
|
+
if (value && String(value).trim()) {
|
|
113
|
+
process.stdout.write(String(value).trim());
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
" 2>/dev/null || true
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
create_npmrc_for_registry() {
|
|
122
|
+
local registry="$1"
|
|
123
|
+
local token="$2"
|
|
124
|
+
local scope_owner="$3"
|
|
125
|
+
local registry_host=""
|
|
126
|
+
registry_host="$(printf '%s' "$registry" | sed -E 's#^https?://##; s#/*$##')"
|
|
127
|
+
|
|
128
|
+
local npmrc_tmp=""
|
|
129
|
+
npmrc_tmp="$(mktemp /tmp/omnizap-release-npmrc.XXXXXX)"
|
|
130
|
+
{
|
|
131
|
+
printf 'registry=%s\n' "$registry"
|
|
132
|
+
if [ -n "$scope_owner" ]; then
|
|
133
|
+
printf '@%s:registry=%s\n' "$scope_owner" "$registry"
|
|
134
|
+
fi
|
|
135
|
+
if [ -n "$token" ]; then
|
|
136
|
+
printf '//%s/:_authToken=%s\n' "$registry_host" "$token"
|
|
137
|
+
printf '//%s:_authToken=%s\n' "$registry_host" "$token"
|
|
138
|
+
fi
|
|
139
|
+
} > "$npmrc_tmp"
|
|
140
|
+
chmod 600 "$npmrc_tmp"
|
|
141
|
+
TMP_NPMRC_FILES+=("$npmrc_tmp")
|
|
142
|
+
printf '%s' "$npmrc_tmp"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
verify_registry_version() {
|
|
146
|
+
local pkg_name="$1"
|
|
147
|
+
local pkg_version="$2"
|
|
148
|
+
local registry="$3"
|
|
149
|
+
local token_keys="$4"
|
|
150
|
+
local auth_required="$5"
|
|
151
|
+
|
|
152
|
+
local token=""
|
|
153
|
+
token="$(resolve_token_from_dotenv "$token_keys")"
|
|
154
|
+
if [ "$auth_required" = "1" ] && [ -z "$token" ]; then
|
|
155
|
+
printf '[release] Verificação em %s requer token (keys: %s).\n' "$registry" "$token_keys" >&2
|
|
156
|
+
exit 1
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
local scope_owner=""
|
|
160
|
+
scope_owner="$(printf '%s' "$pkg_name" | sed -nE 's#^@([^/]+)/.*#\1#p')"
|
|
161
|
+
local npmrc_tmp=""
|
|
162
|
+
npmrc_tmp="$(create_npmrc_for_registry "$registry" "$token" "$scope_owner")"
|
|
163
|
+
|
|
164
|
+
local version_raw=""
|
|
165
|
+
if ! version_raw="$(
|
|
166
|
+
cd "$PROJECT_ROOT" &&
|
|
167
|
+
npm_config_userconfig="$npmrc_tmp" npm view "${pkg_name}@${pkg_version}" version --registry "$registry" --userconfig "$npmrc_tmp" 2>/dev/null
|
|
168
|
+
)"; then
|
|
169
|
+
printf '[release] Falha ao validar versão %s em %s.\n' "$pkg_version" "$registry" >&2
|
|
170
|
+
exit 1
|
|
171
|
+
fi
|
|
172
|
+
local version_value=""
|
|
173
|
+
version_value="$(sanitize_npm_output "$version_raw")"
|
|
174
|
+
if [ "$version_value" != "$pkg_version" ]; then
|
|
175
|
+
printf '[release] Versão divergente em %s: esperado=%s encontrado=%s\n' "$registry" "$pkg_version" "${version_value:-vazio}" >&2
|
|
176
|
+
exit 1
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
local latest_raw=""
|
|
180
|
+
if ! latest_raw="$(
|
|
181
|
+
cd "$PROJECT_ROOT" &&
|
|
182
|
+
npm_config_userconfig="$npmrc_tmp" npm view "$pkg_name" dist-tags.latest --registry "$registry" --userconfig "$npmrc_tmp" 2>/dev/null
|
|
183
|
+
)"; then
|
|
184
|
+
printf '[release] Falha ao validar dist-tag latest em %s.\n' "$registry" >&2
|
|
185
|
+
exit 1
|
|
186
|
+
fi
|
|
187
|
+
local latest_value=""
|
|
188
|
+
latest_value="$(sanitize_npm_output "$latest_raw")"
|
|
189
|
+
if [ "$latest_value" != "$pkg_version" ]; then
|
|
190
|
+
printf '[release] Dist-tag latest divergente em %s: esperado=%s latest=%s\n' "$registry" "$pkg_version" "${latest_value:-vazio}" >&2
|
|
191
|
+
exit 1
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
log "Verificado em $registry: versão=$pkg_version latest=$latest_value"
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
compute_target_version() {
|
|
198
|
+
local current="$1"
|
|
199
|
+
|
|
200
|
+
if [ -n "$RELEASE_FORCE_VERSION" ]; then
|
|
201
|
+
printf '%s' "$RELEASE_FORCE_VERSION"
|
|
202
|
+
return 0
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
if [ "$RELEASE_TYPE" = "patch" ] && [ "$RELEASE_PATCH_ROLLOVER_ENABLED" = "1" ]; then
|
|
206
|
+
if [[ "$RELEASE_PATCH_ROLLOVER_AT" =~ ^[0-9]+$ ]] && [[ "$current" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
|
207
|
+
local major="${BASH_REMATCH[1]}"
|
|
208
|
+
local minor="${BASH_REMATCH[2]}"
|
|
209
|
+
local patch="${BASH_REMATCH[3]}"
|
|
210
|
+
if [ "$patch" -ge "$RELEASE_PATCH_ROLLOVER_AT" ]; then
|
|
211
|
+
printf '%s.%s.0' "$major" "$((minor + 1))"
|
|
212
|
+
return 0
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
printf ''
|
|
218
|
+
}
|
|
219
|
+
|
|
52
220
|
commit_and_push_if_dirty() {
|
|
53
221
|
local commit_message="$1"
|
|
54
222
|
|
|
@@ -86,30 +254,55 @@ commit_and_push_if_dirty() {
|
|
|
86
254
|
|
|
87
255
|
require_cmd git
|
|
88
256
|
require_cmd npm
|
|
257
|
+
require_cmd node
|
|
89
258
|
|
|
90
259
|
if ! (cd "$PROJECT_ROOT" && git rev-parse --is-inside-work-tree >/dev/null 2>&1); then
|
|
91
260
|
printf '[release] este diretório não é um repositório git válido.\n' >&2
|
|
92
261
|
exit 1
|
|
93
262
|
fi
|
|
94
263
|
|
|
264
|
+
if [ "$RELEASE_REQUIRE_GITHUB_RELEASE" = "1" ] && [ "$RELEASE_GITHUB_RELEASE" != "1" ]; then
|
|
265
|
+
printf '[release] RELEASE_REQUIRE_GITHUB_RELEASE=1 exige RELEASE_GITHUB_RELEASE=1.\n' >&2
|
|
266
|
+
exit 1
|
|
267
|
+
fi
|
|
268
|
+
|
|
95
269
|
commit_and_push_if_dirty "$RELEASE_GIT_PRE_COMMIT_MESSAGE"
|
|
96
270
|
|
|
97
271
|
current_version="$(cd "$PROJECT_ROOT" && npm pkg get version | tr -d '"[:space:]')"
|
|
98
272
|
log "Versão atual: $current_version"
|
|
99
|
-
|
|
273
|
+
target_version="$(compute_target_version "$current_version")"
|
|
100
274
|
|
|
101
|
-
|
|
275
|
+
if [ -n "$target_version" ]; then
|
|
276
|
+
if [ "$target_version" = "$current_version" ]; then
|
|
277
|
+
printf '[release] versão alvo igual à versão atual (%s). Verifique regras de bump.\n' "$current_version" >&2
|
|
278
|
+
exit 1
|
|
279
|
+
fi
|
|
280
|
+
log "Aplicando versão alvo: $target_version"
|
|
281
|
+
(cd "$PROJECT_ROOT" && npm version "$target_version" --no-git-tag-version >/dev/null)
|
|
282
|
+
else
|
|
283
|
+
log "Aplicando bump: $RELEASE_TYPE"
|
|
284
|
+
(cd "$PROJECT_ROOT" && npm version "$RELEASE_TYPE" --no-git-tag-version >/dev/null)
|
|
285
|
+
fi
|
|
102
286
|
|
|
103
287
|
new_version="$(cd "$PROJECT_ROOT" && npm pkg get version | tr -d '"[:space:]')"
|
|
104
288
|
log "Nova versão: $new_version"
|
|
105
289
|
|
|
106
290
|
log "Executando deploy com publish de package"
|
|
291
|
+
deploy_publish_primary="${DEPLOY_PACKAGE_PUBLISH:-1}"
|
|
292
|
+
deploy_publish_secondary="${DEPLOY_PACKAGE_PUBLISH_SECONDARY:-1}"
|
|
293
|
+
|
|
294
|
+
if [ "$RELEASE_REQUIRE_DUAL_PUBLISH" = "1" ]; then
|
|
295
|
+
if [ "$deploy_publish_primary" != "1" ] || [ "$deploy_publish_secondary" != "1" ]; then
|
|
296
|
+
printf '[release] RELEASE_REQUIRE_DUAL_PUBLISH=1 exige DEPLOY_PACKAGE_PUBLISH=1 e DEPLOY_PACKAGE_PUBLISH_SECONDARY=1.\n' >&2
|
|
297
|
+
exit 1
|
|
298
|
+
fi
|
|
299
|
+
fi
|
|
107
300
|
|
|
108
301
|
if ! (
|
|
109
302
|
cd "$PROJECT_ROOT"
|
|
110
303
|
DEPLOY_PACKAGE_STEP="${DEPLOY_PACKAGE_STEP:-1}" \
|
|
111
|
-
DEPLOY_PACKAGE_PUBLISH="$
|
|
112
|
-
DEPLOY_PACKAGE_PUBLISH_SECONDARY="$
|
|
304
|
+
DEPLOY_PACKAGE_PUBLISH="$deploy_publish_primary" \
|
|
305
|
+
DEPLOY_PACKAGE_PUBLISH_SECONDARY="$deploy_publish_secondary" \
|
|
113
306
|
DEPLOY_PACKAGE_SECONDARY_REGISTRY="${DEPLOY_PACKAGE_SECONDARY_REGISTRY:-https://registry.npmjs.org}" \
|
|
114
307
|
DEPLOY_PACKAGE_SECONDARY_ACCESS="${DEPLOY_PACKAGE_SECONDARY_ACCESS:-public}" \
|
|
115
308
|
DEPLOY_PACKAGE_INSTALL="${DEPLOY_PACKAGE_INSTALL:-0}" \
|
|
@@ -126,4 +319,71 @@ if [ "$RELEASE_GIT_COMMIT_VERSION" = "1" ]; then
|
|
|
126
319
|
commit_and_push_if_dirty "${RELEASE_GIT_VERSION_COMMIT_PREFIX}${new_version}"
|
|
127
320
|
fi
|
|
128
321
|
|
|
322
|
+
release_tag="${RELEASE_GITHUB_TAG_PREFIX}${new_version}"
|
|
323
|
+
|
|
324
|
+
if [ "$RELEASE_GITHUB_RELEASE" = "1" ]; then
|
|
325
|
+
if [ "$RELEASE_GIT_AUTO_PUSH" != "1" ]; then
|
|
326
|
+
printf '[release] RELEASE_GITHUB_RELEASE=1 requer RELEASE_GIT_AUTO_PUSH=1 para garantir commit acessível no GitHub.\n' >&2
|
|
327
|
+
exit 1
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
local_name="${RELEASE_GITHUB_NAME_PREFIX}${new_version}"
|
|
331
|
+
local_target="$RELEASE_GITHUB_TARGET"
|
|
332
|
+
if [ -z "$local_target" ]; then
|
|
333
|
+
local_target="$(cd "$PROJECT_ROOT" && git rev-parse HEAD)"
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
local_prerelease="$RELEASE_GITHUB_PRERELEASE"
|
|
337
|
+
if [ -z "$local_prerelease" ]; then
|
|
338
|
+
if printf '%s' "$new_version" | grep -q '-'; then
|
|
339
|
+
local_prerelease="1"
|
|
340
|
+
else
|
|
341
|
+
local_prerelease="0"
|
|
342
|
+
fi
|
|
343
|
+
fi
|
|
344
|
+
|
|
345
|
+
local generate_notes_bool=""
|
|
346
|
+
generate_notes_bool="$(to_bool "$RELEASE_GITHUB_GENERATE_NOTES")"
|
|
347
|
+
local prerelease_bool=""
|
|
348
|
+
prerelease_bool="$(to_bool "$local_prerelease")"
|
|
349
|
+
local draft_bool=""
|
|
350
|
+
draft_bool="$(to_bool "$RELEASE_GITHUB_DRAFT")"
|
|
351
|
+
|
|
352
|
+
log "Criando/atualizando GitHub Release ($release_tag)"
|
|
353
|
+
release_output="$(
|
|
354
|
+
cd "$PROJECT_ROOT" && node ./scripts/github-release-notify.mjs upsert \
|
|
355
|
+
--tag "$release_tag" \
|
|
356
|
+
--target "$local_target" \
|
|
357
|
+
--name "$local_name" \
|
|
358
|
+
--generate-notes "$generate_notes_bool" \
|
|
359
|
+
--prerelease "$prerelease_bool" \
|
|
360
|
+
--draft "$draft_bool"
|
|
361
|
+
)"
|
|
362
|
+
log "GitHub Release atualizado: $release_output"
|
|
363
|
+
fi
|
|
364
|
+
|
|
365
|
+
if [ "$RELEASE_VERIFY_UNIFIED_VERSION" = "1" ]; then
|
|
366
|
+
pkg_name="$(cd "$PROJECT_ROOT" && npm pkg get name | tr -d '"[:space:]')"
|
|
367
|
+
if [ -z "$pkg_name" ]; then
|
|
368
|
+
printf '[release] Falha ao ler nome do pacote para verificação final.\n' >&2
|
|
369
|
+
exit 1
|
|
370
|
+
fi
|
|
371
|
+
|
|
372
|
+
local_version_now="$(cd "$PROJECT_ROOT" && npm pkg get version | tr -d '"[:space:]')"
|
|
373
|
+
if [ "$local_version_now" != "$new_version" ]; then
|
|
374
|
+
printf '[release] Versão local divergente após release: esperado=%s encontrado=%s\n' "$new_version" "$local_version_now" >&2
|
|
375
|
+
exit 1
|
|
376
|
+
fi
|
|
377
|
+
log "Verificado localmente: versão=$local_version_now"
|
|
378
|
+
|
|
379
|
+
verify_registry_version "$pkg_name" "$new_version" "$RELEASE_VERIFY_PRIMARY_REGISTRY" "$RELEASE_VERIFY_PRIMARY_TOKEN_KEYS" "1"
|
|
380
|
+
verify_registry_version "$pkg_name" "$new_version" "$RELEASE_VERIFY_SECONDARY_REGISTRY" "$RELEASE_VERIFY_SECONDARY_TOKEN_KEYS" "0"
|
|
381
|
+
|
|
382
|
+
gh_release_check="$(
|
|
383
|
+
cd "$PROJECT_ROOT" && node ./scripts/github-release-notify.mjs get --tag "$release_tag"
|
|
384
|
+
)"
|
|
385
|
+
log "Verificado GitHub Release: $gh_release_check"
|
|
386
|
+
log "Verificação final concluída: todas as versões estão em $new_version"
|
|
387
|
+
fi
|
|
388
|
+
|
|
129
389
|
log "Release concluída: $new_version"
|