Skip to content

Commit 9f0cd1a

Browse files
committed
chore: remove environment variables from expo-doctor workflow
1 parent 83bc3a2 commit 9f0cd1a

File tree

3 files changed

+77
-48
lines changed

3 files changed

+77
-48
lines changed

.env.sample

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
API_URL=https://dummyjson.com/
2-
3-
## TODO: add the variable to your CI and remove it from here, not recommended setting sensitive values on your git repo
4-
SECRET_KEY=my-secret-key
5-
VAR_NUMBER=10 # this is a number variable
6-
VAR_BOOL=true # this is a boolean variable
1+
API_URL=
2+
VAR_NUMBER=
3+
VAR_BOOL=
4+
SECRET_KEY=

.github/workflows/expo-doctor.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,6 @@ jobs:
2828
name: Expo Doctor (expo)
2929
runs-on: ubuntu-latest
3030

31-
env:
32-
# Add your other environment variables here, e.g.:
33-
API_URL: https://dummyjson.com/
34-
SECRET_KEY: my-secret-key
35-
VAR_NUMBER: 10
36-
VAR_BOOL: true
37-
3831
steps:
3932
- name: 📦 Checkout project repo
4033
uses: actions/checkout@v3
@@ -44,8 +37,5 @@ jobs:
4437
- name: 📦 Setup Node + PNPM + install deps
4538
uses: ./.github/actions/setup-node-pnpm-install
4639

47-
- name: Run prebuild
48-
run: pnpm run prebuild ## we only need to run this to generate the badged icon in `.expo` folder
49-
5040
- name: 🚑 Run Doctor Checks
5141
run: rm -rf ios android && pnpm run doctor ## apprently the new update of expo will break if you already have ios and android folders in your project as they will show up a eas warning

env.js

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Env file to load and validate env variables
3-
* Be cautious; this file should not be imported into your source folder.
3+
* Be cautious; this file should not be imported into your source folder. TODO: Add an eslint rule to prevent this.
44
* We split the env variables into two parts:
55
* 1. Client variables: These variables are used in the client-side code (src folder).
66
* 2. Build-time variables: These variables are used in the build process (app.config.ts file).
@@ -16,7 +16,23 @@ const z = require('zod');
1616

1717
const packageJSON = require('./package.json');
1818
const path = require('path');
19-
const APP_ENV = process.env.APP_ENV ?? 'development';
19+
20+
const APP_ENV =
21+
/** @type {z.infer<typeof clientEnvSchema>['APP_ENV']} */
22+
(process.env.APP_ENV) ?? 'development';
23+
24+
const ENVIRONMENT_DEPENDANT_SCRIPTS = [
25+
'expo start',
26+
'expo prebuild',
27+
'eas build',
28+
'expo run',
29+
];
30+
31+
// Check if the environment file has to be validated for the current running script
32+
const shouldValidateEnv = ENVIRONMENT_DEPENDANT_SCRIPTS.some((script) =>
33+
process.env.npm_lifecycle_script?.includes(script)
34+
);
35+
2036
const envPath = path.resolve(__dirname, `.env.${APP_ENV}`);
2137

2238
require('dotenv').config({
@@ -47,9 +63,8 @@ const SCHEME = 'RootstrapApp'; // app scheme
4763
* @returns {string}
4864
*/
4965

50-
const withEnvSuffix = (name) => {
51-
return APP_ENV === 'production' ? name : `${name}.${APP_ENV}`;
52-
};
66+
const withEnvSuffix = (name) =>
67+
APP_ENV === 'production' ? name : `${name}.${APP_ENV}`;
5368

5469
/**
5570
* 2nd part: Define your env variables schema
@@ -69,7 +84,14 @@ const withEnvSuffix = (name) => {
6984
*
7085
*/
7186

72-
const client = z.object({
87+
const parseString = (/** @type {string | undefined} */ value) =>
88+
value === '' ? undefined : value;
89+
const parseNumber = (/** @type {string | undefined} */ value) =>
90+
value ? Number(value) : undefined;
91+
const parseBoolean = (/** @type {string | undefined} */ value) =>
92+
value ? value === 'true' : undefined;
93+
94+
const clientEnvSchema = z.object({
7395
APP_ENV: z.enum(['development', 'staging', 'production']),
7496
NAME: z.string(),
7597
SCHEME: z.string(),
@@ -83,38 +105,38 @@ const client = z.object({
83105
VAR_BOOL: z.boolean(),
84106
});
85107

86-
const buildTime = z.object({
108+
const buildTimeEnvSchema = z.object({
87109
EXPO_ACCOUNT_OWNER: z.string(),
88110
EAS_PROJECT_ID: z.string(),
89111
// ADD YOUR BUILD TIME ENV VARS HERE
90112
SECRET_KEY: z.string(),
91113
});
92114

93115
/**
94-
* @type {Record<keyof z.infer<typeof client> , unknown>}
116+
* @type {Partial<z.infer<typeof clientEnvSchema>>}
95117
*/
96118
const _clientEnv = {
97119
APP_ENV,
98-
NAME: NAME,
99-
SCHEME: SCHEME,
120+
NAME,
121+
SCHEME,
100122
BUNDLE_ID: withEnvSuffix(BUNDLE_ID),
101123
PACKAGE: withEnvSuffix(PACKAGE),
102124
VERSION: packageJSON.version,
103125

104126
// ADD YOUR ENV VARS HERE TOO
105-
API_URL: process.env.API_URL,
106-
VAR_NUMBER: Number(process.env.VAR_NUMBER),
107-
VAR_BOOL: process.env.VAR_BOOL === 'true',
127+
API_URL: parseString(process.env.API_URL),
128+
VAR_NUMBER: parseNumber(process.env.VAR_NUMBER),
129+
VAR_BOOL: parseBoolean(process.env.VAR_BOOL),
108130
};
109131

110132
/**
111-
* @type {Record<keyof z.infer<typeof buildTime> , unknown>}
133+
* @type {Record<keyof z.infer<typeof buildTimeEnvSchema> , unknown>}
112134
*/
113135
const _buildTimeEnv = {
114136
EXPO_ACCOUNT_OWNER,
115137
EAS_PROJECT_ID,
116138
// ADD YOUR ENV VARS HERE TOO
117-
SECRET_KEY: process.env.SECRET_KEY,
139+
SECRET_KEY: parseString(process.env.SECRET_KEY),
118140
};
119141

120142
/**
@@ -123,30 +145,49 @@ const _buildTimeEnv = {
123145
* If the validation fails we throw an error and log the error to the console with a detailed message about missed variables
124146
* If the validation passes we export the merged and parsed env variables to be used in the app.config.ts file as well as a ClientEnv object to be used in the client-side code
125147
**/
126-
const _env = {
148+
149+
const _wholeEnv = {
127150
..._clientEnv,
128151
..._buildTimeEnv,
129152
};
153+
const wholeEnvSchema = buildTimeEnvSchema.merge(clientEnvSchema);
130154

131-
const merged = buildTime.merge(client);
132-
const parsed = merged.safeParse(_env);
133-
134-
if (parsed.success === false) {
135-
console.error(
136-
'❌ Invalid environment variables:',
137-
parsed.error.flatten().fieldErrors,
155+
/**
156+
* @type {z.infer<typeof wholeEnvSchema>}
157+
*/
158+
let Env;
138159

139-
`\n❌ Missing variables in .env.${APP_ENV} file, Make sure all required variables are defined in the .env.${APP_ENV} file.`,
140-
`\n💡 Tip: If you recently updated the .env.${APP_ENV} file and the error still persists, try restarting the server with the -cc flag to clear the cache.`
141-
);
142-
throw new Error(
143-
'Invalid environment variables, Check terminal for more details '
144-
);
160+
/**
161+
* @type {z.infer<typeof clientEnvSchema>}
162+
*/
163+
let ClientEnv;
164+
165+
if (shouldValidateEnv) {
166+
const parsedWholeEnv = wholeEnvSchema.safeParse(_wholeEnv);
167+
168+
if (parsedWholeEnv.success === false) {
169+
console.error(
170+
'❌ Invalid environment variables:',
171+
parsedWholeEnv.error.flatten().fieldErrors,
172+
173+
`\n❌ Missing variables in \x1b[1m\x1b[4m\x1b[31m.env.${APP_ENV}\x1b[0m file, Make sure all required variables are defined in the \x1b[1m\x1b[4m\x1b[31m.env.${APP_ENV}\x1b[0m file.`,
174+
`\n💡 Tip: If you recently updated the .env.${APP_ENV} file and the error still persists, try restarting the server with the -cc flag to clear the cache.`
175+
);
176+
throw new Error(
177+
'Invalid environment variables, Check terminal for more details '
178+
);
179+
}
180+
181+
Env = parsedWholeEnv.data;
182+
ClientEnv = clientEnvSchema.parse(_clientEnv);
183+
} else {
184+
// Don't worry about TypeScript here; if we don't need to validate the env variables is because we aren't using them
185+
//@ts-ignore
186+
Env = _wholeEnv;
187+
//@ts-ignore
188+
ClientEnv = _clientEnv;
145189
}
146190

147-
const Env = parsed.data;
148-
const ClientEnv = client.parse(_clientEnv);
149-
150191
module.exports = {
151192
Env,
152193
ClientEnv,

0 commit comments

Comments
 (0)