submodule-version 1.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 +12 -0
- package/eslint.config.js +15 -0
- package/index.js +162 -0
- package/package.json +20 -0
package/README.md
ADDED
package/eslint.config.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const soft = require('eslint-config-soft');
|
|
2
|
+
const globals = require('globals');
|
|
3
|
+
|
|
4
|
+
module.exports = [
|
|
5
|
+
...soft,
|
|
6
|
+
{
|
|
7
|
+
languageOptions: {
|
|
8
|
+
globals: globals.node,
|
|
9
|
+
sourceType: "commonjs",
|
|
10
|
+
},
|
|
11
|
+
rules: {
|
|
12
|
+
'@typescript-eslint/no-require-imports': 'off',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
];
|
package/index.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const yargs = require('yargs');
|
|
7
|
+
const JSON_NAME = 'package.json';
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const VERSION_REGEX = /(^.*@.*)@(.*)$/;
|
|
10
|
+
const DEFAULT_DIR = 'modules';
|
|
11
|
+
|
|
12
|
+
const logger = (...message) => {
|
|
13
|
+
// eslint-disable-next-line no-console
|
|
14
|
+
console.log(...message);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const abort = (...message) => {
|
|
18
|
+
logger(...message);
|
|
19
|
+
yargs.exit(1, message.join(' '));
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const readProjectJSON = () => {
|
|
23
|
+
const jsonPath = path.join(cwd, JSON_NAME);
|
|
24
|
+
const isJsonExists = fs.existsSync(jsonPath);
|
|
25
|
+
if (!isJsonExists) throw new Error(`${cwd} is not npm project`);
|
|
26
|
+
const jsonString = fs.readFileSync(jsonPath, 'utf-8');
|
|
27
|
+
|
|
28
|
+
return JSON.parse(jsonString);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const writeProjectJSON = data => {
|
|
32
|
+
fs.writeFileSync(path.join(cwd, JSON_NAME), JSON.stringify(data, null, 2));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const isGitUrl = url => url.endsWith('.git');
|
|
36
|
+
|
|
37
|
+
const getName = url => {
|
|
38
|
+
if (isGitUrl(url)) return /\/(.*)\.git/.exec(url)[1];
|
|
39
|
+
const parts = url.split('/');
|
|
40
|
+
|
|
41
|
+
return parts[parts.length - 1];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const install = (url, version, location) => {
|
|
45
|
+
const name = getName(url);
|
|
46
|
+
const targetLocation = path.join(location, name);
|
|
47
|
+
const gitCmd = `git submodule add -b ${version} ${url} ${targetLocation}`;
|
|
48
|
+
try {
|
|
49
|
+
execSync(gitCmd);
|
|
50
|
+
} catch {
|
|
51
|
+
abort(url, 'Is not a git repo');
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const graph = {};
|
|
56
|
+
|
|
57
|
+
const buildGraph = (dependencies = {}, parent, location) => {
|
|
58
|
+
Object.entries(dependencies).forEach(([url, version]) => {
|
|
59
|
+
const name = getName(url);
|
|
60
|
+
const dependencyJSON = path.join(cwd, location, name, JSON_NAME);
|
|
61
|
+
const dependencyIsInstalled = fs.existsSync(dependencyJSON);
|
|
62
|
+
|
|
63
|
+
graph[name] = {
|
|
64
|
+
...(graph[name] || {}),
|
|
65
|
+
[version]: [...(graph[name]?.[version] || []), parent],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (!dependencyIsInstalled) install(url, version, location);
|
|
69
|
+
const jsonString = fs.readFileSync(dependencyJSON, 'utf-8');
|
|
70
|
+
const { wv: depWV = {} } = JSON.parse(jsonString);
|
|
71
|
+
|
|
72
|
+
buildGraph(depWV.dependencies, name, location);
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const computeErrors = () => {
|
|
77
|
+
const errorList = Object.entries(graph).reduce((acc, [name, links]) => {
|
|
78
|
+
if (Object.keys(links).length <= 1) return acc;
|
|
79
|
+
|
|
80
|
+
const err = Object.entries(links).reduce((errAcc, [version, usedBy]) => (
|
|
81
|
+
`${errAcc} Version <${version}> used by: ${usedBy.join(', ')}.`
|
|
82
|
+
), `Confilict in module [${name}]!`);
|
|
83
|
+
|
|
84
|
+
return [...acc, err];
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
87
|
+
return errorList.join('\n');
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const validate = (wv, name) => {
|
|
91
|
+
buildGraph(wv.dependencies, name, wv?.dir || DEFAULT_DIR);
|
|
92
|
+
logger('Everything is up to date.');
|
|
93
|
+
const errors = computeErrors();
|
|
94
|
+
if (!errors) return;
|
|
95
|
+
abort(errors);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const checkoutModule = (url, version) => {
|
|
99
|
+
const module = isGitUrl(url) ? `${DEFAULT_DIR}/${getName(url)}` : url;
|
|
100
|
+
logger('checkout', module);
|
|
101
|
+
try {
|
|
102
|
+
execSync(`git -C ${module} checkout ${version}`);
|
|
103
|
+
} catch {
|
|
104
|
+
abort('Checkout failded');
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const validationCommand = () => {
|
|
109
|
+
const { name, wv } = readProjectJSON();
|
|
110
|
+
validate(wv, name);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const makeInstallCommand = arg => {
|
|
114
|
+
const { url } = arg;
|
|
115
|
+
const versionMatch = VERSION_REGEX.exec(url) || [];
|
|
116
|
+
const [, gitaddress = url, version = 'master'] = versionMatch;
|
|
117
|
+
|
|
118
|
+
if (!isGitUrl(gitaddress)) {
|
|
119
|
+
abort(gitaddress, 'is not a git URL');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const projectJSON = readProjectJSON();
|
|
123
|
+
const installedDep = projectJSON?.wv.dependencies?.[gitaddress];
|
|
124
|
+
|
|
125
|
+
if (installedDep && installedDep !== version) {
|
|
126
|
+
checkoutModule(gitaddress, version);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const wv = {
|
|
130
|
+
...(projectJSON.wv || {}),
|
|
131
|
+
dependencies: {
|
|
132
|
+
...(projectJSON.wv?.dependencies || {}),
|
|
133
|
+
[gitaddress]: version,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
if (!installedDep || installedDep !== version) {
|
|
138
|
+
writeProjectJSON({ ...projectJSON, wv });
|
|
139
|
+
}
|
|
140
|
+
validate(wv, projectJSON.name);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
144
|
+
yargs.scriptName('wv')
|
|
145
|
+
.usage('$0 <cmd> [args]')
|
|
146
|
+
.command(
|
|
147
|
+
['validate', '$0', 'v'],
|
|
148
|
+
'Validate and install modules',
|
|
149
|
+
() => {},
|
|
150
|
+
validationCommand,
|
|
151
|
+
)
|
|
152
|
+
.command(
|
|
153
|
+
['install <url>', 'i'],
|
|
154
|
+
'Install new submodule',
|
|
155
|
+
y => y.positional('url', {
|
|
156
|
+
type: 'string',
|
|
157
|
+
describe: 'git submodule url',
|
|
158
|
+
}),
|
|
159
|
+
makeInstallCommand,
|
|
160
|
+
)
|
|
161
|
+
.help()
|
|
162
|
+
.argv;
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "submodule-version",
|
|
3
|
+
"description": "Git submodule versioning tool",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"bin": {
|
|
6
|
+
"sw": "index.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"lint": "npx eslint"
|
|
10
|
+
},
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"eslint": "9.9.1",
|
|
15
|
+
"eslint-config-soft": "^1.0.5"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"yargs": "^17.7.2"
|
|
19
|
+
}
|
|
20
|
+
}
|