Skip to content

Commit c56b4d7

Browse files
committed
feat: Added support for validating by OS and distro. Added improved install script that works on linux
1 parent f91cffa commit c56b4d7

File tree

9 files changed

+274
-47
lines changed

9 files changed

+274
-47
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"ajv": "^8.12.0",
1616
"ajv-formats": "^3.0.1",
1717
"chalk": "^5.3.0",
18-
"codify-schemas": "1.0.86-beta5",
18+
"codify-schemas": "1.0.86-beta11",
1919
"cors": "^2.8.5",
2020
"debug": "^4.3.4",
2121
"detect-indent": "^7.0.1",
@@ -143,7 +143,7 @@
143143
"start:vm": "npm run build && npm run pack:macos && npm run start:vm",
144144
"deploy": "npm run pkg && npm run notarize && npm run upload"
145145
},
146-
"version": "1.0.0",
146+
"version": "1.0.0-beta1",
147147
"bugs": "https://github.com/kevinwang5658/codify/issues",
148148
"keywords": [
149149
"oclif"

scripts/install-beta.sh

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,81 @@
11
#!/bin/bash
2-
set -e;
3-
# Always clean up tmp dir even if install fails
4-
trap 'rm -rf $TEMP_DIR' EXIT
2+
{
3+
set -e
4+
SUDO=''
5+
if [ "$(id -u)" != "0" ]; then
6+
SUDO='sudo'
7+
echo "This script requires superuser access."
8+
echo "You will be prompted for your password by sudo."
9+
# clear any previous sudo permission
10+
sudo -k
11+
fi
512

6-
if [ $(uname -s) != "Darwin" ]; then
7-
echo "Only macOS systems are currently supported"
8-
exit 1;
9-
fi;
1013

11-
ARCH=$(uname -m)
12-
TEMP_DIR=$(mktemp -d -t "codify")
14+
# run inside sudo
15+
$SUDO bash <<SCRIPT
16+
set -e
1317
14-
echo "Downloading beta installer...";
15-
curl -L -o "$TEMP_DIR/codify-installer.pkg" "https://api.codifycli.com/v2/cli/releases/beta/$ARCH/installer";
16-
echo "Downloaded Codify beta installer";
18+
echoerr() { echo "\$@" 1>&2; }
1719
18-
printf "\nRunning installer... (sudo may be required)\n";
19-
sudo installer -pkg "$TEMP_DIR/codify-installer.pkg" -target /;
20+
if [ "\$(uname)" == "Darwin" ]; then
21+
OS=darwin
22+
elif [ "\$(expr substr \$(uname -s) 1 5)" == "Linux" ]; then
23+
OS=linux
24+
else
25+
echoerr "This installer is only supported on Linux and macOS"
26+
exit 1
27+
fi
2028
21-
CYAN='\033[0;36m'
22-
END_ESCAPE='\033[0m'
29+
ARCH="\$(uname -m)"
30+
if [ "\$ARCH" == "x86_64" ]; then
31+
ARCH=x64
32+
elif [[ "\$ARCH" == aarch* ]]; then
33+
ARCH=arm
34+
elif [[ "\$ARCH" == "arm64" ]]; then
35+
ARCH=arm64
36+
else
37+
echoerr "unsupported arch: \$ARCH"
38+
exit 1
39+
fi
2340
24-
printf "${CYAN}\n🎉 %s 🎉\n%s${END_ESCAPE}\n" "Successfully installed Codify beta. Type codify --help for a list of commands." "Visit the documentation at https://docs.codifycli.com for more info."
41+
if [[ ! ":$PATH:" == *":/usr/local/bin:"* ]]; then
42+
echoerr "Your path is missing /usr/local/bin, you need to add this to use this installer."
43+
exit 1
44+
fi
2545
26-
exit 0;
46+
mkdir -p /usr/local/lib
47+
cd /usr/local/lib
48+
rm -rf codify
49+
rm -rf ~/.local/share/codify/client
50+
# if [ \$(command -v xz) ]; then
51+
# URL=https://releases.codifycli.com/channels/beta/codify-\$OS-\$ARCH.tar.xz
52+
# TAR_ARGS="xJ"
53+
# else
54+
URL=https://releases.codifycli.com/channels/beta/codify-\$OS-\$ARCH.tar.gz
55+
TAR_ARGS="xz"
56+
# fi
57+
echo "Installing CLI from \$URL"
58+
if [ \$(command -v curl) ]; then
59+
curl "\$URL" | tar "\$TAR_ARGS"
60+
else
61+
wget -O- "\$URL" | tar "\$TAR_ARGS"
62+
fi
63+
# delete old codify bin if exists
64+
rm -f \$(command -v codify) || true
65+
rm -f /usr/local/bin/codify
66+
ln -s /usr/local/lib/codify/bin/codify /usr/local/bin/codify
67+
68+
# on alpine (and maybe others) the basic node binary does not work
69+
# remove our node binary and fall back to whatever node is on the PATH
70+
/usr/local/lib/codify/bin/node -v || rm /usr/local/lib/codify/bin/node
71+
72+
SCRIPT
73+
# test the CLI
74+
LOCATION=$(command -v codify)
75+
76+
CYAN='\033[0;36m'
77+
END_ESCAPE='\033[0m'
78+
79+
printf "${CYAN}\n🎉 %s 🎉\n%s${END_ESCAPE}\n" "Successfully installed Codify. Type codify --help for a list of commands." "Visit the documentation at https://docs.codifycli.com for more info."
80+
exit 0;
81+
}

scripts/install.sh

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,81 @@
11
#!/bin/bash
2-
set -e;
3-
# Always clean up tmp dir even if install fails
4-
trap 'rm -rf $TEMP_DIR' EXIT
2+
{
3+
set -e
4+
SUDO=''
5+
if [ "$(id -u)" != "0" ]; then
6+
SUDO='sudo'
7+
echo "This script requires superuser access."
8+
echo "You will be prompted for your password by sudo."
9+
# clear any previous sudo permission
10+
sudo -k
11+
fi
512

6-
if [ $(uname -s) != "Darwin" ]; then
7-
echo "Only macOS systems are currently supported"
8-
exit 1;
9-
fi;
1013

11-
ARCH=$(uname -m)
12-
TEMP_DIR=$(mktemp -d -t "codify")
14+
# run inside sudo
15+
$SUDO bash <<SCRIPT
16+
set -e
1317
14-
echo "Downloading installer...";
15-
curl -L -o "$TEMP_DIR/codify-installer.pkg" "https://api.codifycli.com/v2/cli/releases/stable/$ARCH/installer";
16-
echo "Downloaded Codify installer";
18+
echoerr() { echo "\$@" 1>&2; }
1719
18-
printf "\nRunning installer... (sudo may be required)\n";
19-
sudo installer -pkg "$TEMP_DIR/codify-installer.pkg" -target /;
20+
if [ "\$(uname)" == "Darwin" ]; then
21+
OS=darwin
22+
elif [ "\$(expr substr \$(uname -s) 1 5)" == "Linux" ]; then
23+
OS=linux
24+
else
25+
echoerr "This installer is only supported on Linux and macOS"
26+
exit 1
27+
fi
2028
21-
CYAN='\033[0;36m'
22-
END_ESCAPE='\033[0m'
29+
ARCH="\$(uname -m)"
30+
if [ "\$ARCH" == "x86_64" ]; then
31+
ARCH=x64
32+
elif [[ "\$ARCH" == aarch* ]]; then
33+
ARCH=arm
34+
elif [[ "\$ARCH" == "arm64" ]]; then
35+
ARCH=arm64
36+
else
37+
echoerr "unsupported arch: \$ARCH"
38+
exit 1
39+
fi
2340
24-
printf "${CYAN}\n🎉 %s 🎉\n%s${END_ESCAPE}\n" "Successfully installed Codify. Type codify --help for a list of commands." "Visit the documentation at https://docs.codifycli.com for more info."
41+
if [[ ! ":$PATH:" == *":/usr/local/bin:"* ]]; then
42+
echoerr "Your path is missing /usr/local/bin, you need to add this to use this installer."
43+
exit 1
44+
fi
2545
26-
exit 0;
46+
mkdir -p /usr/local/lib
47+
cd /usr/local/lib
48+
rm -rf codify
49+
rm -rf ~/.local/share/codify/client
50+
if [ \$(command -v xz) ]; then
51+
URL=https://releases.codifycli.com/channels/stable/codify-\$OS-\$ARCH.tar.xz
52+
TAR_ARGS="xJ"
53+
else
54+
URL=https://releases.codifycli.com/channels/stable/codify-\$OS-\$ARCH.tar.gz
55+
TAR_ARGS="xz"
56+
fi
57+
echo "Installing CLI from \$URL"
58+
if [ \$(command -v curl) ]; then
59+
curl "\$URL" | tar "\$TAR_ARGS"
60+
else
61+
wget -O- "\$URL" | tar "\$TAR_ARGS"
62+
fi
63+
# delete old codify bin if exists
64+
rm -f \$(command -v codify) || true
65+
rm -f /usr/local/bin/codify
66+
ln -s /usr/local/lib/codify/bin/codify /usr/local/bin/codify
67+
68+
# on alpine (and maybe others) the basic node binary does not work
69+
# remove our node binary and fall back to whatever node is on the PATH
70+
/usr/local/lib/codify/bin/node -v || rm /usr/local/lib/codify/bin/node
71+
72+
SCRIPT
73+
# test the CLI
74+
LOCATION=$(command -v codify)
75+
76+
CYAN='\033[0;36m'
77+
END_ESCAPE='\033[0m'
78+
79+
printf "${CYAN}\n🎉 %s 🎉\n%s${END_ESCAPE}\n" "Successfully installed Codify. Type codify --help for a list of commands." "Visit the documentation at https://docs.codifycli.com for more info."
80+
exit 0;
81+
}

scripts/pkg.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ execSync('oclif pack macos -r .', { cwd: './.build', shell: 'zsh' });
3838
await patchMacOsInstallers()
3939

4040
console.log(chalk.magenta('Running oclif pkg tarballs'))
41-
execSync('oclif pack tarballs -r . -t darwin-arm64,darwin-x64', { cwd: './.build', shell: 'zsh' })
41+
execSync('oclif pack tarballs -r . -t darwin-arm64,darwin-x64,linux-x64,linux-arm64', { cwd: './.build', shell: 'zsh' })
4242

4343
console.log(chalk.magenta('Copying files back'))
4444
await Promise.all([

src/common/errors.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,63 @@ export class TypeNotFoundError extends CodifyError {
115115
}
116116
}
117117

118+
export class OperatingSystemNotSupportedError extends CodifyError {
119+
invalidConfigs: ResourceConfig[];
120+
sourceMaps?: SourceMapCache;
121+
122+
constructor(invalidConfigs: ResourceConfig[], sourceMaps?: SourceMapCache) {
123+
super('Validation error: invalid operating system found. Resource type is not supported on this operating system.')
124+
125+
this.invalidConfigs = invalidConfigs;
126+
this.sourceMaps = sourceMaps;
127+
}
128+
129+
formattedMessage(): string {
130+
let errorMessage = `${this.message}\n\n`
131+
132+
for (const invalidConfig of this.invalidConfigs) {
133+
if (!invalidConfig.sourceMapKey || !this.sourceMaps) {
134+
errorMessage += `type ${invalidConfig.type} is not valid.`
135+
continue;
136+
}
137+
138+
const codeSnippet = this.sourceMaps?.getCodeSnippet(SourceMapCache.combineKeys(invalidConfig.sourceMapKey!, 'type'))
139+
errorMessage += `Type "${invalidConfig.type}" is not valid\n${codeSnippet}`
140+
}
141+
142+
return errorMessage;
143+
}
144+
}
145+
146+
export class LinuxDistroNotSupportedError extends CodifyError {
147+
invalidConfigs: ResourceConfig[];
148+
sourceMaps?: SourceMapCache;
149+
150+
constructor(invalidConfigs: ResourceConfig[], sourceMaps?: SourceMapCache) {
151+
super('Validation error: invalid Linux distribution found. Resource type is not supported on this Linux distribution.')
152+
153+
this.invalidConfigs = invalidConfigs;
154+
this.sourceMaps = sourceMaps;
155+
}
156+
157+
formattedMessage(): string {
158+
let errorMessage = `${this.message}\n\n`
159+
160+
for (const invalidConfig of this.invalidConfigs) {
161+
if (!invalidConfig.sourceMapKey || !this.sourceMaps) {
162+
errorMessage += `type ${invalidConfig.type} is not valid.`
163+
continue;
164+
}
165+
166+
const codeSnippet = this.sourceMaps?.getCodeSnippet(SourceMapCache.combineKeys(invalidConfig.sourceMapKey!, 'type'))
167+
errorMessage += `Type "${invalidConfig.type}" is not valid\n${codeSnippet}`
168+
}
169+
170+
return errorMessage;
171+
}
172+
}
173+
174+
118175
export class InvalidResourceError extends Error {
119176
name = 'InvalidResourceError'
120177

src/entities/project.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
import { PlanRequestData, ResourceOperation, ValidateResponseData } from 'codify-schemas';
1+
import { OS, PlanRequestData, ResourceOperation, ValidateResponseData } from 'codify-schemas';
2+
import * as os from 'os'
23
import { validate } from 'uuid'
34

4-
import { PluginValidationError, PluginValidationErrorParams, TypeNotFoundError } from '../common/errors.js';
5+
import {
6+
LinuxDistroNotSupportedError,
7+
OperatingSystemNotSupportedError,
8+
PluginValidationError,
9+
PluginValidationErrorParams,
10+
TypeNotFoundError
11+
} from '../common/errors.js';
512
import { ctx } from '../events/context.js';
613
import { SourceMapCache } from '../parser/source-maps.js';
714
import { ResourceDefinitionMap } from '../plugins/plugin-manager.js';
@@ -11,6 +18,7 @@ import { ConfigBlock, ConfigType } from './config.js';
1118
import { type Plan } from './plan.js';
1219
import { ProjectConfig } from './project-config.js';
1320
import { ResourceConfig } from './resource-config.js';
21+
import { ShellUtils } from '../utils/shell.js';
1422

1523
export class Project {
1624
projectConfig: ProjectConfig | null;
@@ -163,6 +171,41 @@ ${JSON.stringify(projectConfigs, null, 2)}`);
163171
}
164172
}
165173

174+
async validateOsAndDistro(resourceDefinitions: ResourceDefinitionMap) {
175+
const invalidConfigs = this.resourceConfigs.filter((c) => {
176+
const operatingSystems = resourceDefinitions.get(c.type)?.operatingSystems;
177+
if (!operatingSystems) {
178+
return true;
179+
}
180+
181+
return operatingSystems.includes(os.type() as OS);
182+
});
183+
184+
if (invalidConfigs.length > 0) {
185+
throw new OperatingSystemNotSupportedError(invalidConfigs, this.sourceMaps);
186+
}
187+
188+
if (os.type() === OS.Linux) {
189+
const currentDistro = await ShellUtils.getLinuxDistro();
190+
if (!currentDistro) {
191+
throw new Error('Unable to determine Linux distribution');
192+
}
193+
194+
this.resourceConfigs.filter((c) => {
195+
const distros = resourceDefinitions.get(c.type)?.linuxDistros;
196+
if (!distros) {
197+
return true;
198+
}
199+
200+
return distros.includes(currentDistro);
201+
});
202+
203+
if (invalidConfigs.length > 0) {
204+
throw new LinuxDistroNotSupportedError(invalidConfigs, this.sourceMaps);
205+
}
206+
}
207+
}
208+
166209
resolveDependenciesAndCalculateEvalOrder(resourceDefinitions?: ResourceDefinitionMap) {
167210
this.resolveResourceDependencies(resourceDefinitions);
168211
this.calculateEvaluationOrder();

src/orchestrators/validate.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export const ValidateOrchestrator = {
3030
}
3131

3232
project.validateTypeIds(resourceDefinitions);
33+
await project.validateOsAndDistro(resourceDefinitions);
34+
3335
const validationResults = await pluginManager.validate(project);
3436
project.handlePluginResourceValidationResults(validationResults);
3537

0 commit comments

Comments
 (0)