@naturalcycles/nodejs-lib 13.32.0 → 13.33.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.
Files changed (37) hide show
  1. package/dist/csv/csvReader.js +2 -2
  2. package/dist/fs/fs2.js +6 -3
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +2 -2
  5. package/dist/slack/slack.service.js +2 -4
  6. package/dist/stream/ndjson/transformJsonParse.js +1 -1
  7. package/dist/stream/transform/transformSplit.js +2 -2
  8. package/dist/stream/transform/worker/workerClassProxy.js +2 -2
  9. package/dist/stream/writable/writableLimit.js +1 -1
  10. package/dist/stream/writable/writableVoid.js +1 -1
  11. package/dist/util/buildInfo.util.js +5 -5
  12. package/dist/util/exec2.d.ts +167 -0
  13. package/dist/util/exec2.js +204 -0
  14. package/dist/util/git2.d.ts +25 -0
  15. package/dist/util/git2.js +95 -0
  16. package/package.json +2 -1
  17. package/src/csv/csvReader.ts +2 -7
  18. package/src/fs/fs2.ts +11 -7
  19. package/src/index.ts +2 -2
  20. package/src/secret/secrets-decrypt.util.ts +1 -1
  21. package/src/secret/secrets-encrypt.util.ts +1 -1
  22. package/src/slack/slack.service.ts +2 -3
  23. package/src/stream/ndjson/transformJsonParse.ts +1 -1
  24. package/src/stream/stream.model.ts +2 -2
  25. package/src/stream/transform/transformSplit.ts +3 -3
  26. package/src/stream/transform/worker/workerClassProxy.js +2 -2
  27. package/src/stream/writable/writableLimit.ts +1 -1
  28. package/src/stream/writable/writableVoid.ts +1 -1
  29. package/src/util/buildInfo.util.ts +5 -10
  30. package/src/util/exec2.ts +326 -0
  31. package/src/util/git2.ts +105 -0
  32. package/dist/util/exec.util.d.ts +0 -10
  33. package/dist/util/exec.util.js +0 -58
  34. package/dist/util/git.util.d.ts +0 -18
  35. package/dist/util/git.util.js +0 -109
  36. package/src/util/exec.util.ts +0 -79
  37. package/src/util/git.util.ts +0 -113
@@ -56,10 +56,7 @@ export function csvStringParse<T extends AnyObject = any>(
56
56
  }
57
57
 
58
58
  export function csvStringToArray(str: string): string[][] {
59
- const objPattern = new RegExp(
60
- String.raw`(,|\r?\n|\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^,\r\n]*))`,
61
- 'gi',
62
- )
59
+ const objPattern = /(,|\r?\n|\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^,\r\n]*))/gi
63
60
  let matches: RegExpExecArray | null
64
61
  const arr: any[][] = [[]]
65
62
 
@@ -67,9 +64,7 @@ export function csvStringToArray(str: string): string[][] {
67
64
  if (matches[1]!.length && matches[1] !== ',') {
68
65
  arr.push([])
69
66
  }
70
- arr[arr.length - 1]!.push(
71
- matches[2] ? matches[2].replaceAll(new RegExp('""', 'g'), '"') : matches[3],
72
- )
67
+ arr[arr.length - 1]!.push(matches[2] ? matches[2].replaceAll('""', '"') : matches[3])
73
68
  }
74
69
  return arr
75
70
  }
package/src/fs/fs2.ts CHANGED
@@ -14,7 +14,7 @@ Credit to: fs-extra (https://github.com/jprichardson/node-fs-extra)
14
14
 
15
15
  */
16
16
 
17
- import type { RmOptions } from 'node:fs'
17
+ import type { RmOptions, Stats } from 'node:fs'
18
18
  import fs from 'node:fs'
19
19
  import fsp from 'node:fs/promises'
20
20
  import path from 'node:path'
@@ -182,7 +182,7 @@ class FS2 {
182
182
  }
183
183
 
184
184
  ensureFile(filePath: string): void {
185
- let stats
185
+ let stats: Stats | undefined
186
186
  try {
187
187
  stats = fs.statSync(filePath)
188
188
  } catch {}
@@ -197,7 +197,10 @@ class FS2 {
197
197
  }
198
198
  } catch (err) {
199
199
  // If the stat call above failed because the directory doesn't exist, create it
200
- if ((err as any)?.code === 'ENOENT') return this.ensureDir(dir)
200
+ if ((err as any)?.code === 'ENOENT') {
201
+ this.ensureDir(dir)
202
+ return
203
+ }
201
204
  throw err
202
205
  }
203
206
 
@@ -205,7 +208,7 @@ class FS2 {
205
208
  }
206
209
 
207
210
  async ensureFileAsync(filePath: string): Promise<void> {
208
- let stats
211
+ let stats: Stats | undefined
209
212
  try {
210
213
  stats = await fsp.stat(filePath)
211
214
  } catch {}
@@ -236,18 +239,19 @@ class FS2 {
236
239
  }
237
240
 
238
241
  emptyDir(dirPath: string): void {
239
- let items
242
+ let items: string[]
240
243
  try {
241
244
  items = fs.readdirSync(dirPath)
242
245
  } catch {
243
- return this.ensureDir(dirPath)
246
+ this.ensureDir(dirPath)
247
+ return
244
248
  }
245
249
 
246
250
  items.forEach(item => this.removePath(path.join(dirPath, item)))
247
251
  }
248
252
 
249
253
  async emptyDirAsync(dirPath: string): Promise<void> {
250
- let items
254
+ let items: string[]
251
255
  try {
252
256
  items = await fsp.readdir(dirPath)
253
257
  } catch {
package/src/index.ts CHANGED
@@ -72,8 +72,8 @@ export * from './stream/writable/writableVoid'
72
72
  export * from './string/inspect'
73
73
  export * from './util/buildInfo.util'
74
74
  export * from './util/env.util'
75
- export * from './util/exec.util'
76
- export * from './util/git.util'
75
+ export * from './util/exec2'
76
+ export * from './util/git2'
77
77
  export * from './util/lruMemoCache'
78
78
  export * from './util/zip.util'
79
79
  export * from './validation/ajv/ajv.util'
@@ -37,7 +37,7 @@ export function secretsDecrypt(
37
37
  const filenames = fastGlob.sync(patterns)
38
38
 
39
39
  filenames.forEach(filename => {
40
- let plainFilename
40
+ let plainFilename: string
41
41
 
42
42
  if (jsonMode) {
43
43
  _assert(filename.endsWith('.json'), `${path.basename(filename)} MUST end with '.json'`)
@@ -31,7 +31,7 @@ export function secretsEncrypt(
31
31
  `!**/*.enc`, // excluding already encoded
32
32
  ]
33
33
  const filenames = fastGlob.sync(patterns)
34
- let encFilename
34
+ let encFilename: string
35
35
 
36
36
  filenames.forEach(filename => {
37
37
  if (jsonMode) {
@@ -92,7 +92,7 @@ export class SlackService<CTX = any> {
92
92
  if (msg.kv) {
93
93
  ;(msg.attachments ||= []).push({ fields: this.kvToFields(msg.kv) })
94
94
 
95
- delete msg.kv // to not pass it all the way to Slack Api
95
+ msg.kv = undefined // to not pass it all the way to Slack Api
96
96
  }
97
97
 
98
98
  let text: string
@@ -135,9 +135,8 @@ export class SlackService<CTX = any> {
135
135
  // ignore (unless throwOnError is set)
136
136
  if (msg.throwOnError) {
137
137
  throw err
138
- } else {
139
- console.log(err)
140
138
  }
139
+ console.log(err)
141
140
  })
142
141
  }
143
142
 
@@ -55,7 +55,7 @@ export function transformJsonParse<ROW = any>(
55
55
  }
56
56
 
57
57
  // Based on: https://stackoverflow.com/a/34557997/4919972
58
- export const bufferReviver: Reviver = (k, v) => {
58
+ export const bufferReviver: Reviver = (_k, v) => {
59
59
  if (v !== null && typeof v === 'object' && v.type === 'Buffer' && Array.isArray(v.data)) {
60
60
  return Buffer.from(v.data)
61
61
  }
@@ -45,7 +45,7 @@ export interface ReadableTyped<T> extends Readable {
45
45
  drop: (limit: number, opt?: ReadableSignalOptions) => ReadableTyped<T>
46
46
  }
47
47
 
48
- // eslint-disable-next-line unused-imports/no-unused-vars
48
+ // biome-ignore lint/correctness/noUnusedVariables: ok
49
49
  export interface WritableTyped<T> extends Writable {}
50
50
 
51
51
  /**
@@ -59,7 +59,7 @@ export type ReadableBinary = Readable
59
59
  */
60
60
  export type WritableBinary = Writable
61
61
 
62
- // eslint-disable-next-line unused-imports/no-unused-vars
62
+ // biome-ignore lint/correctness/noUnusedVariables: ok
63
63
  export interface TransformTyped<IN, OUT> extends Transform {}
64
64
 
65
65
  export interface TransformOptions {
@@ -18,7 +18,7 @@ export function transformSplitOnNewline(): TransformTyped<Buffer, Buffer> {
18
18
  readableObjectMode: true,
19
19
  writableHighWaterMark: 64 * 1024,
20
20
 
21
- transform(buf: Buffer, enc, done) {
21
+ transform(buf: Buffer, _enc, done) {
22
22
  let offset = 0
23
23
  let lastMatch = 0
24
24
  if (buffered) {
@@ -66,7 +66,7 @@ export function transformSplit(separator = '\n'): TransformTyped<Buffer, Buffer>
66
66
  readableObjectMode: true,
67
67
  writableHighWaterMark: 64 * 1024,
68
68
 
69
- transform(buf: Buffer, enc, done) {
69
+ transform(buf: Buffer, _enc, done) {
70
70
  let offset = 0
71
71
  let lastMatch = 0
72
72
  if (buffered) {
@@ -119,7 +119,7 @@ function firstNewlineMatch(buf: Buffer, offset: number): number {
119
119
 
120
120
  function firstMatch(buf: Buffer, offset: number, matcher: Buffer): number {
121
121
  if (offset >= buf.length) return -1
122
- let i
122
+ let i: number
123
123
  for (i = offset; i < buf.length; i++) {
124
124
  if (buf[i] === matcher[0]) {
125
125
  if (matcher.length > 1) {
@@ -1,6 +1,6 @@
1
1
  const started = Date.now()
2
- const { workerData, parentPort } = require('worker_threads')
3
- const { inspect } = require('util')
2
+ const { workerData, parentPort } = require('node:worker_threads')
3
+ const { inspect } = require('node:util')
4
4
  const { workerFile, workerIndex, logEvery = 1000, metric = 'worker' } = workerData || {}
5
5
 
6
6
  if (!workerFile) {
@@ -11,7 +11,7 @@ export function writableLimit<T>(readable: Readable, limit: number): WritableTyp
11
11
 
12
12
  return new Writable({
13
13
  objectMode: true,
14
- write(chunk, _, cb) {
14
+ write(_chunk, _, cb) {
15
15
  if (limit === 0) return cb() // no limit, just passthrough
16
16
 
17
17
  i++
@@ -18,7 +18,7 @@ export function writableVoid(opt: WritableVoidOptions = {}): Writable {
18
18
  return new Writable({
19
19
  objectMode: true,
20
20
  ...opt,
21
- write(chunk, _, cb) {
21
+ write(_chunk, _, cb) {
22
22
  cb()
23
23
  },
24
24
  final(cb) {
@@ -6,12 +6,7 @@ import {
6
6
  UnixTimestampNumber,
7
7
  } from '@naturalcycles/js-lib'
8
8
  import { fs2 } from '../fs/fs2'
9
- import {
10
- gitCurrentBranchName,
11
- gitCurrentCommitSha,
12
- gitCurrentCommitTimestamp,
13
- gitCurrentRepoName,
14
- } from './git.util'
9
+ import { git2 } from './git2'
15
10
 
16
11
  export interface GenerateBuildInfoOptions {
17
12
  /**
@@ -24,10 +19,10 @@ export function generateBuildInfo(opt: GenerateBuildInfoOptions = {}): BuildInfo
24
19
  const now = localTime.orNow(opt.overrideTimestamp)
25
20
  const ts = now.unix
26
21
 
27
- const rev = gitCurrentCommitSha()
28
- const branchName = gitCurrentBranchName()
29
- const repoName = gitCurrentRepoName()
30
- const tsCommit = gitCurrentCommitTimestamp()
22
+ const rev = git2.gitCurrentCommitSha()
23
+ const branchName = git2.gitCurrentBranchName()
24
+ const repoName = git2.gitCurrentRepoName()
25
+ const tsCommit = git2.gitCurrentCommitTimestamp()
31
26
 
32
27
  const ver = [now.toStringCompact(), repoName, branchName, rev].join('_')
33
28
 
@@ -0,0 +1,326 @@
1
+ import cp from 'node:child_process'
2
+ import {
3
+ _since,
4
+ AnyObject,
5
+ AppError,
6
+ NumberOfMilliseconds,
7
+ UnixTimestampMillisNumber,
8
+ } from '@naturalcycles/js-lib'
9
+ import { dimGrey, white } from '../colors/colors'
10
+
11
+ /**
12
+ * Set of utility functions to work with Spawn / Exec.
13
+ *
14
+ * How to decide between Spawn and Exec?
15
+ *
16
+ * Long-running job that prints output, and no need to return the output - use Spawn.
17
+ *
18
+ * Short-running job, no need to print the output, might want to return the output - use Exec.
19
+ *
20
+ * Need to both print and return the output - use SpawnAsync.
21
+ *
22
+ * ***
23
+ *
24
+ * Spawn is good for long-running large-output processes, that continuously output data.
25
+ * E.g running `jest`.
26
+ *
27
+ * Exec is the opposite - good for short-running processes that output small data.
28
+ * Exec allows to return the output as a string.
29
+ * Exec doesn't stream data during execution, so the output/error will only be printed
30
+ * at the end.
31
+ * Exec always uses the shell (there's no option to disable it).
32
+ */
33
+ class Exec2 {
34
+ /**
35
+ * Advanced/async version of Spawn.
36
+ * Consider simpler `spawn` or `exec` first, which are also sync.
37
+ *
38
+ * spawnAsync features:
39
+ *
40
+ * 1. Async
41
+ * 2. Allows to collect the output AND print it while running.
42
+ * 3. Returns SpawnOutput with stdout, stderr and exitCode.
43
+ * 4. Allows to not throw on error, but just return SpawnOutput for further inspection.
44
+ *
45
+ * Defaults:
46
+ *
47
+ * shell: true
48
+ * printWhileRunning: true
49
+ * collectOutputWhileRunning: true
50
+ * throwOnNonZeroCode: true
51
+ * log: true
52
+ */
53
+ async spawnAsync(cmd: string, opt: SpawnAsyncOptions = {}): Promise<SpawnOutput> {
54
+ const started = Date.now()
55
+ this.logStart(cmd, opt)
56
+ const {
57
+ shell = true,
58
+ printWhileRunning = true,
59
+ collectOutputWhileRunning = true,
60
+ throwOnNonZeroCode = true,
61
+ cwd,
62
+ env,
63
+ } = opt
64
+ let stdout = ''
65
+ let stderr = ''
66
+
67
+ return await new Promise<SpawnOutput>((resolve, reject) => {
68
+ const p = cp.spawn(cmd, opt.args || [], {
69
+ shell,
70
+ cwd,
71
+ env,
72
+ // ...process.env, // not passing by default for security reasons
73
+ })
74
+
75
+ p.stdout.on('data', data => {
76
+ if (collectOutputWhileRunning) {
77
+ stdout += data.toString()
78
+ // console.log('stdout:', data.toString())
79
+ }
80
+ if (printWhileRunning) {
81
+ process.stdout.write(data)
82
+ // console.log('stderr:', data.toString())
83
+ }
84
+ })
85
+ p.stderr.on('data', data => {
86
+ if (collectOutputWhileRunning) {
87
+ stderr += data.toString()
88
+ }
89
+ if (printWhileRunning) {
90
+ process.stderr.write(data)
91
+ }
92
+ })
93
+
94
+ p.on('close', code => {
95
+ this.logFinish(cmd, opt, started)
96
+ const exitCode = code || 0
97
+ const o: SpawnOutput = {
98
+ exitCode,
99
+ stdout: stdout.trim(),
100
+ stderr: stderr.trim(),
101
+ }
102
+ if (throwOnNonZeroCode && code) {
103
+ return reject(new SpawnError(`spawnAsync exited with code ${code}: ${cmd}`, o))
104
+ }
105
+ resolve(o)
106
+ })
107
+ })
108
+ }
109
+
110
+ /**
111
+ * Reasons to use it:
112
+ * - Sync
113
+ * - Need to print output while running
114
+ *
115
+ * Limitations:
116
+ * - Cannot return stdout/stderr (use exec or spawnAsync for that)
117
+ *
118
+ * Defaults:
119
+ *
120
+ * shell: true
121
+ * log: true
122
+ */
123
+ spawn(cmd: string, opt: SpawnOptions = {}): void {
124
+ const started = Date.now()
125
+ this.logStart(cmd, opt)
126
+ const { shell = true, cwd, env } = opt
127
+
128
+ const r = cp.spawnSync(cmd, opt.args, {
129
+ encoding: 'utf8',
130
+ stdio: 'inherit',
131
+ shell,
132
+ cwd,
133
+ env,
134
+ // ...process.env, // not passing by default for security reasons
135
+ })
136
+
137
+ this.logFinish(cmd, opt, started)
138
+
139
+ if (r.error) {
140
+ throw r.error
141
+ }
142
+ if (r.status) {
143
+ throw new Error(`spawn exited with code ${r.status}: ${cmd}`)
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Reasons to use it:
149
+ *
150
+ * - Sync
151
+ * - Need to return output
152
+ *
153
+ * Limitations:
154
+ * - Cannot print while running (use spawn or spawnAsync for that)
155
+ *
156
+ * Defaults:
157
+ *
158
+ * shell: true
159
+ * log: true
160
+ */
161
+ exec(cmd: string, opt: ExecOptions = {}): string {
162
+ const started = Date.now()
163
+ this.logStart(cmd, opt)
164
+ const { cwd, env, timeout } = opt
165
+
166
+ try {
167
+ return cp
168
+ .execSync(cmd, {
169
+ encoding: 'utf8',
170
+ // stdio: 'inherit', // no, otherwise we don't get the output returned
171
+ stdio: undefined,
172
+ // shell: undefined,
173
+ cwd,
174
+ timeout,
175
+ env,
176
+ // ...process.env, // not passing by default for security reasons
177
+ })
178
+ .trim()
179
+ } catch (err) {
180
+ // Not logging stderr, as it's printed by execSync by default (somehow)
181
+ // stdout is not printed by execSync though, therefor we print it here
182
+ // if ((err as any).stderr) {
183
+ // process.stderr.write((err as any).stderr)
184
+ // }
185
+ if ((err as any).stdout) {
186
+ process.stdout.write((err as any).stdout)
187
+ }
188
+ throw new Error(`exec exited with code ${(err as any).status}: ${cmd}`)
189
+ } finally {
190
+ this.logFinish(cmd, opt, started)
191
+ }
192
+ }
193
+
194
+ throwOnNonZeroExitCode(o: SpawnOutput): void {
195
+ if (o.exitCode) {
196
+ throw new SpawnError(`spawn exited with code ${o.exitCode}`, o)
197
+ }
198
+ }
199
+
200
+ private logStart(cmd: string, opt: SpawnOptions | ExecOptions): void {
201
+ if (!opt.logStart && !opt.log) return
202
+
203
+ console.log(
204
+ [
205
+ dimGrey(...Object.entries(opt.env || {}).map(([k, v]) => [k, v].join('='))),
206
+ white(opt.name || cmd),
207
+ ...((!opt.name && (opt as SpawnOptions).args) || []),
208
+ ]
209
+ .filter(Boolean)
210
+ .join(' '),
211
+ )
212
+ }
213
+
214
+ private logFinish(
215
+ cmd: string,
216
+ opt: SpawnOptions | ExecOptions,
217
+ started: UnixTimestampMillisNumber,
218
+ ): void {
219
+ if (!opt.logFinish && !opt.log) return
220
+
221
+ console.log([white(opt.name || cmd), dimGrey('took ' + _since(started))].join(' '))
222
+ }
223
+ }
224
+
225
+ export const exec2 = new Exec2()
226
+
227
+ export class SpawnError extends AppError<SpawnErrorData> {
228
+ constructor(message: string, data: SpawnErrorData) {
229
+ super(message, data, { name: 'SpawnError' })
230
+ }
231
+ }
232
+
233
+ export interface SpawnErrorData extends SpawnOutput {}
234
+
235
+ export interface SpawnOutput {
236
+ /**
237
+ * Exit code of the spawned process.
238
+ * 0 means success, anything else means failure.
239
+ */
240
+ exitCode: number
241
+ stdout: string
242
+ stderr: string
243
+ }
244
+
245
+ export interface SpawnAsyncOptions extends SpawnOptions {
246
+ /**
247
+ * Defaults to true.
248
+ * If true - prints both stdout and stderr to console while running,
249
+ * otherwise runs "silently".
250
+ * Returns SpawnOutput in the same way, regardless of `printWhileRunning` setting.
251
+ */
252
+ printWhileRunning?: boolean
253
+
254
+ /**
255
+ * Defaults to true.
256
+ * If true - collects stdout and stderr while running, and return it in the end.
257
+ * stdout/stderr are collected and returned regardless if it returns with error or not.
258
+ * On success - stdout/stderr are available from `SpawnOutput`.
259
+ * On error - stdout/stderr are available from `SpawnError.data`.
260
+ */
261
+ collectOutputWhileRunning?: boolean
262
+
263
+ /**
264
+ * Defaults to true.
265
+ * If true - throws SpawnError if non-zero code is returned.
266
+ * SpawnError conveniently contains .data.stdout and .data.strerr for inspection.
267
+ * If false - will not throw, but return SpawnOutput with stdout, stderr and exitCode.
268
+ */
269
+ throwOnNonZeroCode?: boolean
270
+ }
271
+
272
+ export interface SpawnOptions {
273
+ args?: string[]
274
+ /**
275
+ * Defaults to true.
276
+ */
277
+ logStart?: boolean
278
+ /**
279
+ * Defaults to true.
280
+ */
281
+ logFinish?: boolean
282
+ /**
283
+ * Defaults to true.
284
+ * Controls/overrides both logStart and logFinish simultaneously.
285
+ */
286
+ log?: boolean
287
+ /**
288
+ * Defaults to true.
289
+ */
290
+ shell?: boolean
291
+
292
+ /**
293
+ * If specified - will be used as "command name" for logging purposes,
294
+ * instead of "cmd + args"
295
+ */
296
+ name?: string
297
+ cwd?: string
298
+
299
+ env?: AnyObject
300
+ }
301
+
302
+ export interface ExecOptions {
303
+ /**
304
+ * Defaults to false.
305
+ */
306
+ logStart?: boolean
307
+ /**
308
+ * Defaults to false.
309
+ */
310
+ logFinish?: boolean
311
+ /**
312
+ * Defaults to false.
313
+ * Controls/overrides both logStart and logFinish simultaneously.
314
+ */
315
+ log?: boolean
316
+
317
+ /**
318
+ * If specified - will be used as "command name" for logging purposes,
319
+ * instead of "cmd + args"
320
+ */
321
+ name?: string
322
+ cwd?: string
323
+ timeout?: NumberOfMilliseconds
324
+
325
+ env?: AnyObject
326
+ }
@@ -0,0 +1,105 @@
1
+ import cp from 'node:child_process'
2
+ import path from 'node:path'
3
+ import type { UnixTimestampNumber } from '@naturalcycles/js-lib'
4
+ import { grey } from '../colors/colors'
5
+ import { exec2 } from './exec2'
6
+
7
+ /**
8
+ * Set of utility functions to work with git.
9
+ */
10
+ class Git2 {
11
+ getLastGitCommitMsg(): string {
12
+ return exec2.exec('git log -1 --pretty=%B')
13
+ }
14
+
15
+ commitMessageToTitleMessage(msg: string): string {
16
+ const firstLine = msg.split('\n')[0]!
17
+ const [preTitle, title] = firstLine.split(': ')
18
+ return title || preTitle!
19
+ }
20
+
21
+ gitHasUncommittedChanges(): boolean {
22
+ // git diff-index --quiet HEAD -- || echo "untracked"
23
+ try {
24
+ cp.execSync('git diff-index --quiet HEAD --', {
25
+ encoding: 'utf8',
26
+ })
27
+ return false
28
+ } catch {
29
+ return true
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Returns true if there were changes
35
+ */
36
+ gitCommitAll(msg: string): boolean {
37
+ // git commit -a -m "style(lint-all): $GIT_MSG" || true
38
+ const cmd = `git commit -a --no-verify -m "${msg}"`
39
+ // const cmd = `git`
40
+ // const args = ['commit', '-a', '--no-verify', '-m', msg]
41
+ console.log(grey(cmd))
42
+
43
+ try {
44
+ cp.execSync(cmd, {
45
+ stdio: 'inherit',
46
+ })
47
+ return true
48
+ } catch {
49
+ return false
50
+ }
51
+ }
52
+
53
+ /**
54
+ * @returns true if there are not pushed commits.
55
+ */
56
+ gitIsAhead(): boolean {
57
+ // ahead=`git rev-list HEAD --not --remotes | wc -l | awk '{print $1}'`
58
+ const cmd = `git rev-list HEAD --not --remotes | wc -l | awk '{print $1}'`
59
+ const stdout = exec2.exec(cmd)
60
+ // console.log(`gitIsAhead: ${stdout}`)
61
+ return Number(stdout) > 0
62
+ }
63
+
64
+ gitPull(): void {
65
+ const cmd = 'git pull'
66
+ try {
67
+ cp.execSync(cmd, {
68
+ stdio: 'inherit',
69
+ })
70
+ } catch {}
71
+ }
72
+
73
+ gitPush(): void {
74
+ // git push --set-upstream origin $CIRCLE_BRANCH && echo "pushed, exiting" && exit 0
75
+ let cmd = 'git push'
76
+
77
+ const branchName = this.gitCurrentBranchName()
78
+
79
+ if (branchName) {
80
+ cmd += ` --set-upstream origin ${branchName}`
81
+ }
82
+
83
+ exec2.spawn(cmd, { logStart: true })
84
+ }
85
+
86
+ gitCurrentCommitSha(full = false): string {
87
+ const sha = exec2.exec('git rev-parse HEAD')
88
+ return full ? sha : sha.slice(0, 7)
89
+ }
90
+
91
+ gitCurrentCommitTimestamp(): UnixTimestampNumber {
92
+ return Number(exec2.exec('git log -1 --format=%ct'))
93
+ }
94
+
95
+ gitCurrentBranchName(): string {
96
+ return exec2.exec('git rev-parse --abbrev-ref HEAD')
97
+ }
98
+
99
+ gitCurrentRepoName(): string {
100
+ const originUrl = exec2.exec('git config --get remote.origin.url')
101
+ return path.basename(originUrl, '.git')
102
+ }
103
+ }
104
+
105
+ export const git2 = new Git2()
@@ -1,10 +0,0 @@
1
- import type { SpawnOptions } from 'node:child_process';
2
- export interface ExecOptions extends SpawnOptions {
3
- /**
4
- * Defaults to true.
5
- * Set to false to skip logging.
6
- */
7
- log?: boolean;
8
- }
9
- export declare function execVoidCommand(cmd: string, args?: string[], opt?: ExecOptions): Promise<void>;
10
- export declare function execVoidCommandSync(cmd: string, args?: string[], opt?: ExecOptions): void;