proceger 2.0.4 → 2.0.6
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/lib/app.js +1 -1
- package/lib/task_manager.js +3 -3
- package/package.json +3 -3
- package/static/app.js +57 -61
- package/static/e.js +94 -0
- package/static/index.html +1 -1
- package/systemd/system/proceger.service +11 -0
- package/test/task.js +2 -2
package/lib/app.js
CHANGED
package/lib/task_manager.js
CHANGED
|
@@ -4,19 +4,19 @@ const Git = require('./git');
|
|
|
4
4
|
class TaskManager {
|
|
5
5
|
#tasks = {};
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
loadFromConfig(config) {
|
|
8
8
|
const workspace = config.workspace;
|
|
9
9
|
for (const taskConfig of config.tasks) {
|
|
10
|
-
|
|
10
|
+
this.addTask(workspace, taskConfig, config.pollUpdatesInterval);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
async addTask(workspace, config, pollUpdatesInterval) {
|
|
15
15
|
const git = new Git(workspace, config.git.url);
|
|
16
16
|
const task = new Task(config, git, pollUpdatesInterval);
|
|
17
|
+
this.#tasks[task.getName()] = task;
|
|
17
18
|
await task.start();
|
|
18
19
|
await task.pollUpdates();
|
|
19
|
-
this.#tasks[task.getName()] = task;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
getTask(name) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proceger",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "A process manager with web interface.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"glob-promise": "^3.4.0",
|
|
27
27
|
"rc": "^1.2.8",
|
|
28
28
|
"serve-static": "^1.14.1",
|
|
29
|
-
"simple-git": "^
|
|
29
|
+
"simple-git": "^3.3.0",
|
|
30
30
|
"tree-kill": "^1.2.2",
|
|
31
31
|
"uikit": "^3.6.16",
|
|
32
32
|
"winston": "^3.3.3",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"chai-as-promised": "^5.3.0",
|
|
39
39
|
"eslint": "^7.19.0",
|
|
40
40
|
"eslint-config-google": "^0.14.0",
|
|
41
|
-
"mocha": "^
|
|
41
|
+
"mocha": "^10.1.0",
|
|
42
42
|
"sinon": "^9.2.4"
|
|
43
43
|
},
|
|
44
44
|
"bugs": {
|
package/static/app.js
CHANGED
|
@@ -1,70 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
if (type === undefined) {
|
|
3
|
-
return document.getElementById(id);
|
|
4
|
-
}
|
|
5
|
-
const elm = document.createElement(type);
|
|
6
|
-
for (const [key, value] of Object.entries(attributes)) {
|
|
7
|
-
elm.setAttribute(key, value);
|
|
8
|
-
}
|
|
9
|
-
if (typeof children === 'string') {
|
|
10
|
-
elm.innerHTML = children;
|
|
11
|
-
} else {
|
|
12
|
-
for (const child of children) {
|
|
13
|
-
elm.appendChild(child);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
if (id) {
|
|
17
|
-
if (typeof id === 'string') {
|
|
18
|
-
$(id).appendChild(elm);
|
|
19
|
-
} else {
|
|
20
|
-
id.appendChild(elm);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return elm;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
$$ = function(type, attributes, children) {
|
|
27
|
-
return $(null, type, attributes, children);
|
|
28
|
-
};
|
|
1
|
+
import e from './e.js';
|
|
29
2
|
|
|
30
3
|
window.onload = async function() {
|
|
31
4
|
const res = await fetch('/task/list');
|
|
32
5
|
const tasks = await res.json();
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
]
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
'
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
6
|
+
e('tasks-tab', {}, tasks.map((task) => {
|
|
7
|
+
return ['li', {}, ['a', {'href': ''}, task.name]];
|
|
8
|
+
}));
|
|
9
|
+
e('tasks-content', {}, tasks.map((task) => ['li', {}, [
|
|
10
|
+
['div', {}, [
|
|
11
|
+
['ul', {'class': 'uk-list'}, [
|
|
12
|
+
['li', {}, `PID: ${task.pid}`],
|
|
13
|
+
['li', {}, `Repository: ${task.git}`],
|
|
14
|
+
['li', {}, `Revision: ${task.revision}`],
|
|
15
|
+
['li', {}, `Start time: ${new Date(task.startTime)}`],
|
|
16
|
+
]],
|
|
17
|
+
]],
|
|
18
|
+
['p', {
|
|
19
|
+
'uk-margin': '',
|
|
20
|
+
}, [
|
|
21
|
+
['button', {
|
|
22
|
+
'class': 'uk-button uk-button-default',
|
|
23
|
+
'onclick': () => {
|
|
24
|
+
fetch(`/task/${task.name}/stop`);
|
|
25
|
+
},
|
|
26
|
+
}, 'Stop'],
|
|
27
|
+
['span', {}, ' '],
|
|
28
|
+
['button', {
|
|
29
|
+
'class': 'uk-button uk-button-default',
|
|
30
|
+
'onclick': () => {
|
|
31
|
+
fetch(`/task/${task.name}/restart`);
|
|
32
|
+
},
|
|
33
|
+
}, 'Restart'],
|
|
34
|
+
]],
|
|
35
|
+
['ul', {
|
|
36
|
+
'id': `task-${task.name}-logs-tab`,
|
|
37
|
+
'class': 'uk-tab',
|
|
38
|
+
'data-uk-tab': `{connect:'#task-${task.name}-logs'}`,
|
|
39
|
+
},
|
|
40
|
+
Object.keys(task.logs).map((filename, index, files) => {
|
|
41
|
+
return ['li', {
|
|
42
|
+
'class': index === files.length - 1 ? 'uk-active' : '',
|
|
43
|
+
}, [
|
|
44
|
+
['a', {'href': ''}, filename],
|
|
45
|
+
]];
|
|
46
|
+
}),
|
|
47
|
+
],
|
|
48
|
+
['ul', {
|
|
49
|
+
'id': `task-${task.name}-logs`,
|
|
50
|
+
'class': 'uk-switcher uk-margin',
|
|
51
|
+
},
|
|
52
|
+
Object.entries(task.logs).map(([filename, logs]) => {
|
|
53
|
+
return ['li', {}, [[
|
|
54
|
+
'div', {'class': 'logs'}, logs.split('\n').map((line) => {
|
|
60
55
|
try {
|
|
61
56
|
const log = JSON.parse(line);
|
|
62
|
-
return
|
|
57
|
+
return ['p', {}, `${log.timestamp} ${log.message}`];
|
|
63
58
|
} catch (e) {
|
|
64
|
-
return
|
|
59
|
+
return ['p', {}, line];
|
|
65
60
|
}
|
|
66
|
-
})
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
|
|
61
|
+
}),
|
|
62
|
+
]]];
|
|
63
|
+
}),
|
|
64
|
+
],
|
|
65
|
+
]]));
|
|
70
66
|
};
|
package/static/e.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* e is a general purpose function to manipulate HTML DOM elements. In general
|
|
3
|
+
* it will return a DOMElement as a result.
|
|
4
|
+
*
|
|
5
|
+
* If the first argument is a string, it will return the element matching with
|
|
6
|
+
* that ID, or null if not elements is associated with that ID. The subsequce
|
|
7
|
+
* arguments will be used for update its attribute and children. For example,
|
|
8
|
+
*
|
|
9
|
+
* e('div1') is equivalent to document.getElementById('div1').
|
|
10
|
+
* e('div', {'style': 'color: red'}, 'Hello world') is equivalent to the
|
|
11
|
+
* following statements:
|
|
12
|
+
*
|
|
13
|
+
* const div = document.getElementById('div1');
|
|
14
|
+
* div.setAttribute('style', 'color: red');
|
|
15
|
+
* div.innerHTML = 'Hello world';
|
|
16
|
+
*
|
|
17
|
+
* If the param is an array, creates an HTML element based on the items in the
|
|
18
|
+
* array and return the element. The array should be in the form of the
|
|
19
|
+
* following:
|
|
20
|
+
*
|
|
21
|
+
* element := [type, {attributes...}, children]
|
|
22
|
+
* children := [elements...]|text
|
|
23
|
+
*
|
|
24
|
+
* If the children is a list of array, construct the children recursively and
|
|
25
|
+
* append to the current node. If the children is a string, simply set the
|
|
26
|
+
* node's innerHTML.
|
|
27
|
+
*
|
|
28
|
+
* @return {HTMLElement}
|
|
29
|
+
*/
|
|
30
|
+
const e = function(...args) {
|
|
31
|
+
const getElement = function(param) {
|
|
32
|
+
return document.getElementById(param);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const setAttributes = function(elm, attributes) {
|
|
36
|
+
if (typeof attributes !== 'object') {
|
|
37
|
+
throw new Error(`Attributes must be an object, but got ${attributes}.`);
|
|
38
|
+
}
|
|
39
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
40
|
+
if (key.startsWith('on')) {
|
|
41
|
+
elm.addEventListener(key.substr(2), value);
|
|
42
|
+
} else {
|
|
43
|
+
elm.setAttribute(key, value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const updateChildren = function(elm, children) {
|
|
49
|
+
if (typeof children === 'string') {
|
|
50
|
+
elm.innerHTML = children;
|
|
51
|
+
} else if (children instanceof Array) {
|
|
52
|
+
elm.innerHTML = '';
|
|
53
|
+
if (children.length > 0 && !(children[0] instanceof Array)) {
|
|
54
|
+
children = [children];
|
|
55
|
+
}
|
|
56
|
+
for (const child of children) {
|
|
57
|
+
const childElm = buildElement(child);
|
|
58
|
+
elm.appendChild(childElm);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
throw new Error('Attributes must be an object');
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const buildElement = function(param) {
|
|
66
|
+
const [type, attributes, children] = param;
|
|
67
|
+
const elm = document.createElement(type);
|
|
68
|
+
if (attributes !== undefined) {
|
|
69
|
+
setAttributes(elm, attributes);
|
|
70
|
+
}
|
|
71
|
+
if (children !== undefined) {
|
|
72
|
+
updateChildren(elm, children);
|
|
73
|
+
}
|
|
74
|
+
return elm;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
let elm;
|
|
78
|
+
if (typeof args[0] === 'string' || args[0] instanceof String) {
|
|
79
|
+
elm = getElement(args[0]);
|
|
80
|
+
if (args.length >= 2) {
|
|
81
|
+
setAttributes(elm, args[1]);
|
|
82
|
+
}
|
|
83
|
+
if (args.length >= 3) {
|
|
84
|
+
updateChildren(elm, args[2]);
|
|
85
|
+
}
|
|
86
|
+
} else if (args[0] instanceof Array) {
|
|
87
|
+
elm = buildElement(args[0]);
|
|
88
|
+
} else {
|
|
89
|
+
throw new Error(`Unsupported arguments ${args}.`);
|
|
90
|
+
}
|
|
91
|
+
return elm;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export {e as default};
|
package/static/index.html
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<link rel="stylesheet" href="css/uikit.min.css" />
|
|
10
10
|
<script src="js/uikit.min.js"></script>
|
|
11
11
|
<script src="js/uikit-icons.min.js"></script>
|
|
12
|
-
<script src="app.js"></script>
|
|
12
|
+
<script type="module" src="app.js"></script>
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<h1 class="uk-heading-bullet">Proceger</h1>
|
package/test/task.js
CHANGED
|
@@ -73,8 +73,8 @@ describe('Task', function() {
|
|
|
73
73
|
json.should.deep.equal({
|
|
74
74
|
'git': 'git@github.com:sarosia/repo1.git',
|
|
75
75
|
'logs': {
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
'stdout.log': 'log1\nlog2\nlog3\n',
|
|
77
|
+
'stderr.log': 'log1\nlog2\nlog3\n',
|
|
78
78
|
},
|
|
79
79
|
'name': 'repo1',
|
|
80
80
|
'path': repo1Path,
|