safelaunch 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/bin/deploycheck.js +14 -0
- package/env.manifest.json +20 -0
- package/package.json +15 -0
- package/src/validate.js +95 -0
- package/write-action.js +33 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
const command = args[0];
|
|
5
|
+
|
|
6
|
+
if (command === 'validate') {
|
|
7
|
+
require('../src/validate.js');
|
|
8
|
+
} else {
|
|
9
|
+
console.log('\ndeploycheck - Backend Reliability Infrastructure\n');
|
|
10
|
+
console.log('Usage:');
|
|
11
|
+
console.log(
|
|
12
|
+
' deploycheck validate Check your environment against the manifest\n'
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1",
|
|
3
|
+
"runtime": {
|
|
4
|
+
"node": "20"
|
|
5
|
+
},
|
|
6
|
+
"variables": {
|
|
7
|
+
"DATABASE_URL": {
|
|
8
|
+
"required": true,
|
|
9
|
+
"description": "PostgreSQL connection string"
|
|
10
|
+
},
|
|
11
|
+
"REDIS_URL": {
|
|
12
|
+
"required": true,
|
|
13
|
+
"description": "Redis connection string"
|
|
14
|
+
},
|
|
15
|
+
"API_KEY": {
|
|
16
|
+
"required": true,
|
|
17
|
+
"description": "External API key"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "safelaunch",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Backend Reliability Infrastructure - catch what breaks production before it breaks",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"safelaunch": "./bin/deploycheck.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["deployment", "environment", "reliability", "devops"],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "ISC"
|
|
15
|
+
}
|
package/src/validate.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function readManifest() {
|
|
5
|
+
const manifestPath = path.join(process.cwd(), 'env.manifest.json');
|
|
6
|
+
if (!fs.existsSync(manifestPath)) {
|
|
7
|
+
console.log('❌ env.manifest.json not found');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
return JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function readEnv() {
|
|
14
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
15
|
+
if (!fs.existsSync(envPath)) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
const lines = fs.readFileSync(envPath, 'utf8').split('\n');
|
|
19
|
+
const env = {};
|
|
20
|
+
lines.forEach((line) => {
|
|
21
|
+
const [key, value] = line.split('=');
|
|
22
|
+
if (key && key.trim()) {
|
|
23
|
+
env[key.trim()] = value ? value.trim() : '';
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return env;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function checkRuntime(manifest) {
|
|
30
|
+
if (!manifest.runtime || !manifest.runtime.node) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const requiredVersion = manifest.runtime.node;
|
|
35
|
+
const actualVersion = process.versions.node.split('.')[0];
|
|
36
|
+
|
|
37
|
+
if (actualVersion !== requiredVersion) {
|
|
38
|
+
return {
|
|
39
|
+
required: requiredVersion,
|
|
40
|
+
actual: actualVersion,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function validate() {
|
|
48
|
+
console.log('\nRunning deploycheck...\n');
|
|
49
|
+
|
|
50
|
+
const manifest = readManifest();
|
|
51
|
+
const env = readEnv();
|
|
52
|
+
const variables = manifest.variables;
|
|
53
|
+
|
|
54
|
+
const missing = [];
|
|
55
|
+
const passing = [];
|
|
56
|
+
const runtimeMismatch = checkRuntime(manifest);
|
|
57
|
+
|
|
58
|
+
Object.keys(variables).forEach((key) => {
|
|
59
|
+
if (variables[key].required && !env[key]) {
|
|
60
|
+
missing.push(key);
|
|
61
|
+
} else {
|
|
62
|
+
passing.push(key);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (runtimeMismatch) {
|
|
67
|
+
console.log('❌ RUNTIME MISMATCH\n');
|
|
68
|
+
console.log(` Node.js required: v${runtimeMismatch.required}`);
|
|
69
|
+
console.log(` Node.js found: v${runtimeMismatch.actual}\n`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (missing.length > 0) {
|
|
73
|
+
console.log(`❌ MISSING VARIABLES (${missing.length} found)\n`);
|
|
74
|
+
missing.forEach((key) => {
|
|
75
|
+
console.log(` ${key} required but missing from .env`);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (passing.length > 0) {
|
|
80
|
+
console.log(`\n✅ PASSING (${passing.length})\n`);
|
|
81
|
+
passing.forEach((key) => {
|
|
82
|
+
console.log(` ${key} present`);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (runtimeMismatch || missing.length > 0) {
|
|
87
|
+
console.log('\nYour environment is not ready for production.');
|
|
88
|
+
console.log('Fix the issues above and run deploycheck again.\n');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
} else {
|
|
91
|
+
console.log('\nAll clear. Your environment is ready for production.\n');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
validate();
|
package/write-action.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
const content = `name: deploycheck
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: ["main"]
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: ["main"]
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
validate-environment:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout code
|
|
17
|
+
uses: actions/checkout@v3
|
|
18
|
+
|
|
19
|
+
- name: Setup Node.js
|
|
20
|
+
uses: actions/setup-node@v3
|
|
21
|
+
with:
|
|
22
|
+
node-version: "20"
|
|
23
|
+
|
|
24
|
+
- name: Install deploycheck
|
|
25
|
+
run: npm install -g .
|
|
26
|
+
|
|
27
|
+
- name: Run deploycheck
|
|
28
|
+
run: deploycheck validate
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
fs.mkdirSync('.github/workflows', { recursive: true });
|
|
32
|
+
fs.writeFileSync('.github/workflows/deploycheck.yml', content);
|
|
33
|
+
console.log('GitHub Action file created successfully');
|