trackfw 6.10.0 → 7.0.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/README.md +0 -3
- package/package.json +1 -1
- package/src/branch/runner.js +33 -20
- package/src/changelog/index.js +114 -0
- package/src/commands/branch.js +12 -9
- package/src/commands/changelog.js +29 -0
- package/src/commands/commit.js +60 -0
- package/src/commands/discover.js +69 -0
- package/src/commands/index.js +22 -4
- package/src/commands/integrations.js +7 -0
- package/src/commands/ship.js +4 -3
- package/src/commands/thirdparty.js +384 -0
- package/src/commands/update-harness.js +3 -1
- package/src/commands/update.js +3 -1
- package/src/commit/runner.js +352 -0
- package/src/config/index.js +27 -0
- package/src/generators/hooks.js +479 -2
- package/src/generators/init.js +28 -6
- package/src/i18n/locales/en-US.json +1 -19
- package/src/i18n/locales/es-ES.json +1 -19
- package/src/i18n/locales/pt-BR.json +1 -19
- package/src/integrations/index.js +19 -2
- package/src/integrations/manager.js +15 -2
- package/src/lib/unknown-command.js +82 -0
- package/src/ship/runner.js +213 -26
- package/src/thirdparty/fetch.js +140 -0
- package/src/thirdparty/markers.js +207 -0
- package/src/thirdparty/provenance.js +114 -0
- package/src/thirdparty/quarantine.js +113 -0
- package/src/thirdparty/references.js +194 -0
- package/src/validator/index.js +715 -16
- package/src/commands/plugins.js +0 -184
package/src/commands/plugins.js
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const { Command } = require('commander')
|
|
3
|
-
const os = require('os')
|
|
4
|
-
const path = require('path')
|
|
5
|
-
const fs = require('fs')
|
|
6
|
-
const https = require('https')
|
|
7
|
-
const { t } = require('../i18n')
|
|
8
|
-
|
|
9
|
-
const REGISTRY_URL = 'https://raw.githubusercontent.com/kgsaran/trackfw-plugins/main/registry.yaml'
|
|
10
|
-
const MAX_PLUGIN_SIZE = 50 * 1024 * 1024
|
|
11
|
-
const REQUEST_TIMEOUT_MS = 30000
|
|
12
|
-
|
|
13
|
-
function fetchRegistry() {
|
|
14
|
-
return new Promise((resolve, reject) => {
|
|
15
|
-
https.get(REGISTRY_URL, (res) => {
|
|
16
|
-
let data = ''
|
|
17
|
-
res.on('data', chunk => { data += chunk })
|
|
18
|
-
res.on('end', () => resolve(data))
|
|
19
|
-
}).on('error', reject)
|
|
20
|
-
})
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function parseRegistryYAML(text) {
|
|
24
|
-
const entries = []
|
|
25
|
-
let current = null
|
|
26
|
-
const lines = text.split('\n')
|
|
27
|
-
for (const line of lines) {
|
|
28
|
-
const trimmed = line.trim()
|
|
29
|
-
if (!trimmed || trimmed === 'plugins:') continue
|
|
30
|
-
if (trimmed.startsWith('- name:')) {
|
|
31
|
-
if (current) entries.push(current)
|
|
32
|
-
current = { name: trimmed.slice('- name:'.length).trim(), repo: '', description: '', tags: [] }
|
|
33
|
-
continue
|
|
34
|
-
}
|
|
35
|
-
if (!current) continue
|
|
36
|
-
if (trimmed.startsWith('repo:')) {
|
|
37
|
-
current.repo = trimmed.slice('repo:'.length).trim()
|
|
38
|
-
} else if (trimmed.startsWith('description:')) {
|
|
39
|
-
let desc = trimmed.slice('description:'.length).trim()
|
|
40
|
-
desc = desc.replace(/^"|"$/g, '')
|
|
41
|
-
current.description = desc
|
|
42
|
-
} else if (trimmed.startsWith('tags:')) {
|
|
43
|
-
const raw = trimmed.slice('tags:'.length).trim().replace(/^\[|\]$/g, '')
|
|
44
|
-
current.tags = raw.split(',').map(s => s.trim()).filter(Boolean)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (current) entries.push(current)
|
|
48
|
-
return entries
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function matchesKeyword(entry, kw) {
|
|
52
|
-
const lkw = kw.toLowerCase()
|
|
53
|
-
if (entry.name.toLowerCase().includes(lkw)) return true
|
|
54
|
-
if (entry.description.toLowerCase().includes(lkw)) return true
|
|
55
|
-
for (const tag of entry.tags) {
|
|
56
|
-
if (tag.toLowerCase().includes(lkw)) return true
|
|
57
|
-
}
|
|
58
|
-
return false
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function pluginsDir() {
|
|
62
|
-
return path.join(os.homedir(), '.trackfw', 'plugins')
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function platformOS() {
|
|
66
|
-
if (process.platform === 'win32') return 'windows'
|
|
67
|
-
if (process.platform === 'darwin') return 'darwin'
|
|
68
|
-
return 'linux'
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function platformArch() {
|
|
72
|
-
if (process.arch === 'x64') return 'amd64'
|
|
73
|
-
return process.arch
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function listPlugins() {
|
|
77
|
-
const dir = pluginsDir()
|
|
78
|
-
fs.mkdirSync(dir, { recursive: true })
|
|
79
|
-
return fs.readdirSync(dir).filter(f => fs.statSync(path.join(dir, f)).isFile())
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async function installPlugin(repo) {
|
|
83
|
-
let base = repo
|
|
84
|
-
let tag = 'latest'
|
|
85
|
-
const atIdx = repo.indexOf('@')
|
|
86
|
-
if (atIdx !== -1) {
|
|
87
|
-
base = repo.slice(0, atIdx)
|
|
88
|
-
tag = repo.slice(atIdx + 1)
|
|
89
|
-
}
|
|
90
|
-
const pluginName = path.basename(base)
|
|
91
|
-
const assetName = `trackfw-plugin-${pluginName}-${platformOS()}-${platformArch()}`
|
|
92
|
-
const url = tag === 'latest'
|
|
93
|
-
? `https://github.com/${base}/releases/latest/download/${assetName}`
|
|
94
|
-
: `https://github.com/${base}/releases/download/${tag}/${assetName}`
|
|
95
|
-
|
|
96
|
-
const res = await fetch(url, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) })
|
|
97
|
-
if (!res.ok) throw new Error(t('errors.downloadFailed', { status: res.status, url }))
|
|
98
|
-
const declaredSize = Number(res.headers.get('content-length') || 0)
|
|
99
|
-
if (declaredSize > MAX_PLUGIN_SIZE) throw new Error(`Plugin exceeds ${MAX_PLUGIN_SIZE} bytes`)
|
|
100
|
-
|
|
101
|
-
const dir = pluginsDir()
|
|
102
|
-
fs.mkdirSync(dir, { recursive: true })
|
|
103
|
-
const content = Buffer.from(await res.arrayBuffer())
|
|
104
|
-
if (content.length > MAX_PLUGIN_SIZE) throw new Error(`Plugin exceeds ${MAX_PLUGIN_SIZE} bytes`)
|
|
105
|
-
const destination = path.join(dir, pluginName)
|
|
106
|
-
const temporary = path.join(dir, `.${pluginName}-${process.pid}.tmp`)
|
|
107
|
-
try {
|
|
108
|
-
fs.writeFileSync(temporary, content, { mode: 0o755 })
|
|
109
|
-
fs.renameSync(temporary, destination)
|
|
110
|
-
} finally {
|
|
111
|
-
if (fs.existsSync(temporary)) fs.unlinkSync(temporary)
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function removePlugin(name) {
|
|
116
|
-
if (!name || path.basename(name) !== name) throw new Error(`Invalid plugin name: ${name}`)
|
|
117
|
-
const filePath = path.join(pluginsDir(), name)
|
|
118
|
-
if (!fs.existsSync(filePath)) throw new Error(t('errors.pluginNotFound', { name }))
|
|
119
|
-
fs.unlinkSync(filePath)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const cmd = new Command('plugins')
|
|
123
|
-
cmd.description(t('plugins.description'))
|
|
124
|
-
|
|
125
|
-
cmd.command('list')
|
|
126
|
-
.description(t('plugins.list.description'))
|
|
127
|
-
.action(() => {
|
|
128
|
-
const plugins = listPlugins()
|
|
129
|
-
if (plugins.length === 0) {
|
|
130
|
-
console.log(t('plugins.list.empty'))
|
|
131
|
-
return
|
|
132
|
-
}
|
|
133
|
-
plugins.forEach(p => console.log(p))
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
cmd.command('add <repo>')
|
|
137
|
-
.description(t('plugins.add.description'))
|
|
138
|
-
.action(async (repo) => {
|
|
139
|
-
try {
|
|
140
|
-
console.log(t('plugins.add.installing', { repo }))
|
|
141
|
-
await installPlugin(repo)
|
|
142
|
-
const name = repo.split('@')[0].split('/').pop()
|
|
143
|
-
console.log(t('plugins.add.success', { name }))
|
|
144
|
-
} catch (err) {
|
|
145
|
-
console.error(`Error: ${err.message}`)
|
|
146
|
-
process.exit(1)
|
|
147
|
-
}
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
cmd.command('remove <name>')
|
|
151
|
-
.description(t('plugins.remove.description'))
|
|
152
|
-
.action((name) => {
|
|
153
|
-
try {
|
|
154
|
-
removePlugin(name)
|
|
155
|
-
console.log(t('plugins.remove.success', { name }))
|
|
156
|
-
} catch (err) {
|
|
157
|
-
console.error(`Error: ${err.message}`)
|
|
158
|
-
process.exit(1)
|
|
159
|
-
}
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
cmd.command('search <keyword>')
|
|
163
|
-
.description('Search the plugin registry')
|
|
164
|
-
.action(async (keyword) => {
|
|
165
|
-
let entries
|
|
166
|
-
try {
|
|
167
|
-
const body = await fetchRegistry()
|
|
168
|
-
entries = parseRegistryYAML(body).filter(e => matchesKeyword(e, keyword))
|
|
169
|
-
} catch (err) {
|
|
170
|
-
console.log(`Registry unavailable: ${err.message}`)
|
|
171
|
-
return
|
|
172
|
-
}
|
|
173
|
-
if (entries.length === 0) {
|
|
174
|
-
console.log(`No plugins found for "${keyword}"`)
|
|
175
|
-
return
|
|
176
|
-
}
|
|
177
|
-
console.log(String('NAME').padEnd(30) + String('REPO').padEnd(30) + 'DESCRIPTION')
|
|
178
|
-
console.log('-'.repeat(90))
|
|
179
|
-
for (const e of entries) {
|
|
180
|
-
console.log(e.name.padEnd(30) + e.repo.padEnd(30) + e.description)
|
|
181
|
-
}
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
module.exports = cmd
|