Skip to content

Commit 7924bc1

Browse files
authored
Merge pull request #32 from umuttopalak/fix/alembic-err-git-err
feat: enhance Git pull and Alembic migration handling
2 parents c255ce3 + 7f9589d commit 7924bc1

5 files changed

Lines changed: 347 additions & 67 deletions

File tree

dist/index.js

Lines changed: 97 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -172,22 +172,22 @@ function parseAndCheckAlembic(response, source_directory) {
172172
const output = response.output;
173173
if (!output) {
174174
console.log("No output found in the response.");
175-
return false;
175+
return { exists: false };
176176
}
177-
const lines = output.split("\r\n").filter((line) => line.trim() !== "");
178-
const alembicFound = lines.some((line) => line.includes("****"));
179-
if (alembicFound) {
180-
console.log("Alembic found!");
181-
return true;
177+
const lines = output.split(/\r?\n/).filter((line) => line.trim() !== "");
178+
const alembicIniPath = lines.find((line) => line.includes("alembic.ini"));
179+
if (alembicIniPath) {
180+
console.log("Alembic configuration found!");
181+
return { exists: true, path: alembicIniPath.trim() };
182182
}
183183
else {
184-
console.log("Alembic not found!");
185-
return false;
184+
console.log("Alembic configuration not found, skipping migrations");
185+
return { exists: false };
186186
}
187187
}
188188
catch (error) {
189189
console.error(`Error during Alembic check: ${error.message}`);
190-
return false;
190+
return { exists: false };
191191
}
192192
});
193193
}
@@ -231,14 +231,55 @@ function setupWebApp(baseWebAppUrl, api_token, domain_name) {
231231
}
232232
});
233233
}
234+
function checkGitPullOutput(response) {
235+
return __awaiter(this, void 0, void 0, function* () {
236+
try {
237+
const output = response.output;
238+
if (!output) {
239+
return { success: true };
240+
}
241+
const lines = output.split(/\r?\n/).filter((line) => line.trim() !== "");
242+
if (lines.some(line => line.includes("Already up to date"))) {
243+
console.log("Repository is already up to date");
244+
return { success: true };
245+
}
246+
const hasLocalChanges = lines.some(line => line.includes("Your local changes to the following files would be overwritten by merge"));
247+
const hasUntrackedFiles = lines.some(line => line.includes("untracked working tree files would be overwritten by merge"));
248+
const hasError = lines.some(line => line.startsWith("error:"));
249+
if (hasLocalChanges) {
250+
return {
251+
success: false,
252+
error: "local_changes"
253+
};
254+
}
255+
else if (hasUntrackedFiles) {
256+
return {
257+
success: false,
258+
error: "untracked_files"
259+
};
260+
}
261+
else if (hasError) {
262+
return {
263+
success: false,
264+
error: "git_error"
265+
};
266+
}
267+
return { success: true };
268+
}
269+
catch (error) {
270+
console.error(`Error during Git pull check: ${error.message}`);
271+
return { success: false, error: "unknown" };
272+
}
273+
});
274+
}
234275
function run() {
235276
return __awaiter(this, void 0, void 0, function* () {
236277
try {
237278
const username = core.getInput("username", { required: true });
238279
const api_token = core.getInput("api_token", { required: true });
239280
const host = core.getInput("host", { required: true });
240281
const domain_name = core.getInput("domain_name", { required: false }) || null;
241-
const framework_type = core.getInput("framework_type", { required: false }) || "flask";
282+
const framework_type = core.getInput("framework_type", { required: false }) || "django";
242283
const baseApiUrl = `https://${host}/api/v0/user/${username}`;
243284
const baseConsoleUrl = `${baseApiUrl}/consoles/`;
244285
const baseWebAppUrl = `${baseApiUrl}/webapps/`;
@@ -251,15 +292,37 @@ function run() {
251292
const consoleRequestUrl = `${baseApiUrl}/consoles/${consoleId}/send_input/`;
252293
// Git Pull
253294
try {
254-
yield postConsoleInput(consoleRequestUrl, api_token, `git -C ${web_app.source_directory} pull\n`, "Repository Pulled.");
295+
yield postConsoleInput(consoleRequestUrl, api_token, `git -C ${web_app.source_directory} pull\n`, "Checking repository status...");
296+
const pullResponse = yield getLatestConsoleOutput(baseApiUrl, consoleId, api_token, "Git pull completed");
297+
const pullCheck = yield checkGitPullOutput(pullResponse);
298+
if (!pullCheck.success) {
299+
switch (pullCheck.error) {
300+
case "local_changes":
301+
console.error(`Git pull failed: Local changes detected in ${web_app.source_directory}. \n` +
302+
"Please either: \n1) Commit changes (git add . && git commit -m 'message'), \n" +
303+
"2) Stash them (git stash), or \n" +
304+
"3) Remove them (git reset --hard origin/main)\n");
305+
throw new Error("Git pull failed due to local changes");
306+
case "untracked_files":
307+
console.error(`Git pull failed: Untracked files detected in ${web_app.source_directory}. ` +
308+
"Please either: 1) Add files (git add .) or " +
309+
"2) Remove them (git clean -f)");
310+
throw new Error("Git pull failed due to untracked files");
311+
case "git_error":
312+
default:
313+
console.error("Git pull failed. Please check your repository configuration and try again.");
314+
throw new Error("Git pull failed");
315+
}
316+
}
317+
console.log("Repository updated successfully.");
255318
}
256319
catch (error) {
257320
if (error.message.includes("Console not yet started")) {
258321
const consoleUrl = _console.console_url;
259322
throw new Error(`Activate your terminal: ${host}${consoleUrl}`);
260323
}
261324
else {
262-
throw new Error(`Error during pulling repository: ${error.message}`);
325+
throw error;
263326
}
264327
}
265328
if (framework_type == 'django') {
@@ -280,15 +343,30 @@ function run() {
280343
}
281344
else if (framework_type == 'flask') {
282345
try {
283-
const alembicIniPath = `${web_app.source_directory}/alembic.ini`;
284-
yield postConsoleInput(consoleRequestUrl, api_token, `find ${web_app.source_directory} -type f -name "alembic.ini" -print\n`, "Alembic configuration check completed.");
285-
const alembicResponse = yield getLatestConsoleOutput(baseApiUrl, consoleId, api_token, "Alembic.ini Checking.");
286-
const isAlembicUsing = yield parseAndCheckAlembic(alembicResponse, web_app.source_directory);
287346
yield postConsoleInput(consoleRequestUrl, api_token, `source ${web_app.virtualenv_path}/bin/activate\n`, "Virtual Environment Activated.");
288347
yield postConsoleInput(consoleRequestUrl, api_token, `pip install -r ${web_app.source_directory}/requirements.txt\n`, "Requirements Installed.");
289-
if (isAlembicUsing) {
290-
console.log("Alembic migration starting...");
291-
yield postConsoleInput(consoleRequestUrl, api_token, `alembic upgrade head\n`, "Alembic migrations applied.");
348+
yield postConsoleInput(consoleRequestUrl, api_token, `find ${web_app.source_directory} -type f -name "alembic.ini" -print\n`, "Checking for alembic.ini");
349+
const alembicResponse = yield getLatestConsoleOutput(baseApiUrl, consoleId, api_token, "Alembic check completed");
350+
const alembicCheck = yield parseAndCheckAlembic(alembicResponse, web_app.source_directory);
351+
if (alembicCheck.exists && alembicCheck.path) {
352+
try {
353+
console.log("Alembic configuration found, running migrations...");
354+
yield postConsoleInput(consoleRequestUrl, api_token, `cd $(dirname $(find ${web_app.source_directory} -type f -name "alembic.ini" -print -quit)) && alembic upgrade head\n`, "Checking alembic status");
355+
const alembicUpgradeResponse = yield getLatestConsoleOutput(baseApiUrl, consoleId, api_token, "");
356+
if (alembicUpgradeResponse.output && alembicUpgradeResponse.output.includes("FAILED")) {
357+
console.error("Alembic migration failed. Please check your alembic configuration.");
358+
console.error(alembicUpgradeResponse.output);
359+
}
360+
else {
361+
console.log("Alembic migrations completed successfully");
362+
}
363+
}
364+
catch (error) {
365+
console.error(`Error during alembic migration: ${error.message}`);
366+
}
367+
}
368+
else {
369+
console.log("No Alembic configuration found, skipping migrations");
292370
}
293371
}
294372
catch (error) {

lib/index.js

Lines changed: 97 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -165,22 +165,22 @@ function parseAndCheckAlembic(response, source_directory) {
165165
const output = response.output;
166166
if (!output) {
167167
console.log("No output found in the response.");
168-
return false;
168+
return { exists: false };
169169
}
170-
const lines = output.split("\r\n").filter((line) => line.trim() !== "");
171-
const alembicFound = lines.some((line) => line.includes("****"));
172-
if (alembicFound) {
173-
console.log("Alembic found!");
174-
return true;
170+
const lines = output.split(/\r?\n/).filter((line) => line.trim() !== "");
171+
const alembicIniPath = lines.find((line) => line.includes("alembic.ini"));
172+
if (alembicIniPath) {
173+
console.log("Alembic configuration found!");
174+
return { exists: true, path: alembicIniPath.trim() };
175175
}
176176
else {
177-
console.log("Alembic not found!");
178-
return false;
177+
console.log("Alembic configuration not found, skipping migrations");
178+
return { exists: false };
179179
}
180180
}
181181
catch (error) {
182182
console.error(`Error during Alembic check: ${error.message}`);
183-
return false;
183+
return { exists: false };
184184
}
185185
});
186186
}
@@ -224,14 +224,55 @@ function setupWebApp(baseWebAppUrl, api_token, domain_name) {
224224
}
225225
});
226226
}
227+
function checkGitPullOutput(response) {
228+
return __awaiter(this, void 0, void 0, function* () {
229+
try {
230+
const output = response.output;
231+
if (!output) {
232+
return { success: true };
233+
}
234+
const lines = output.split(/\r?\n/).filter((line) => line.trim() !== "");
235+
if (lines.some(line => line.includes("Already up to date"))) {
236+
console.log("Repository is already up to date");
237+
return { success: true };
238+
}
239+
const hasLocalChanges = lines.some(line => line.includes("Your local changes to the following files would be overwritten by merge"));
240+
const hasUntrackedFiles = lines.some(line => line.includes("untracked working tree files would be overwritten by merge"));
241+
const hasError = lines.some(line => line.startsWith("error:"));
242+
if (hasLocalChanges) {
243+
return {
244+
success: false,
245+
error: "local_changes"
246+
};
247+
}
248+
else if (hasUntrackedFiles) {
249+
return {
250+
success: false,
251+
error: "untracked_files"
252+
};
253+
}
254+
else if (hasError) {
255+
return {
256+
success: false,
257+
error: "git_error"
258+
};
259+
}
260+
return { success: true };
261+
}
262+
catch (error) {
263+
console.error(`Error during Git pull check: ${error.message}`);
264+
return { success: false, error: "unknown" };
265+
}
266+
});
267+
}
227268
function run() {
228269
return __awaiter(this, void 0, void 0, function* () {
229270
try {
230271
const username = core.getInput("username", { required: true });
231272
const api_token = core.getInput("api_token", { required: true });
232273
const host = core.getInput("host", { required: true });
233274
const domain_name = core.getInput("domain_name", { required: false }) || null;
234-
const framework_type = core.getInput("framework_type", { required: false }) || "flask";
275+
const framework_type = core.getInput("framework_type", { required: false }) || "django";
235276
const baseApiUrl = `https://${host}/api/v0/user/${username}`;
236277
const baseConsoleUrl = `${baseApiUrl}/consoles/`;
237278
const baseWebAppUrl = `${baseApiUrl}/webapps/`;
@@ -244,15 +285,37 @@ function run() {
244285
const consoleRequestUrl = `${baseApiUrl}/consoles/${consoleId}/send_input/`;
245286
// Git Pull
246287
try {
247-
yield postConsoleInput(consoleRequestUrl, api_token, `git -C ${web_app.source_directory} pull\n`, "Repository Pulled.");
288+
yield postConsoleInput(consoleRequestUrl, api_token, `git -C ${web_app.source_directory} pull\n`, "Checking repository status...");
289+
const pullResponse = yield getLatestConsoleOutput(baseApiUrl, consoleId, api_token, "Git pull completed");
290+
const pullCheck = yield checkGitPullOutput(pullResponse);
291+
if (!pullCheck.success) {
292+
switch (pullCheck.error) {
293+
case "local_changes":
294+
console.error(`Git pull failed: Local changes detected in ${web_app.source_directory}. \n` +
295+
"Please either: \n1) Commit changes (git add . && git commit -m 'message'), \n" +
296+
"2) Stash them (git stash), or \n" +
297+
"3) Remove them (git reset --hard origin/main)\n");
298+
throw new Error("Git pull failed due to local changes");
299+
case "untracked_files":
300+
console.error(`Git pull failed: Untracked files detected in ${web_app.source_directory}. ` +
301+
"Please either: 1) Add files (git add .) or " +
302+
"2) Remove them (git clean -f)");
303+
throw new Error("Git pull failed due to untracked files");
304+
case "git_error":
305+
default:
306+
console.error("Git pull failed. Please check your repository configuration and try again.");
307+
throw new Error("Git pull failed");
308+
}
309+
}
310+
console.log("Repository updated successfully.");
248311
}
249312
catch (error) {
250313
if (error.message.includes("Console not yet started")) {
251314
const consoleUrl = _console.console_url;
252315
throw new Error(`Activate your terminal: ${host}${consoleUrl}`);
253316
}
254317
else {
255-
throw new Error(`Error during pulling repository: ${error.message}`);
318+
throw error;
256319
}
257320
}
258321
if (framework_type == 'django') {
@@ -273,15 +336,30 @@ function run() {
273336
}
274337
else if (framework_type == 'flask') {
275338
try {
276-
const alembicIniPath = `${web_app.source_directory}/alembic.ini`;
277-
yield postConsoleInput(consoleRequestUrl, api_token, `find ${web_app.source_directory} -type f -name "alembic.ini" -print\n`, "Alembic configuration check completed.");
278-
const alembicResponse = yield getLatestConsoleOutput(baseApiUrl, consoleId, api_token, "Alembic.ini Checking.");
279-
const isAlembicUsing = yield parseAndCheckAlembic(alembicResponse, web_app.source_directory);
280339
yield postConsoleInput(consoleRequestUrl, api_token, `source ${web_app.virtualenv_path}/bin/activate\n`, "Virtual Environment Activated.");
281340
yield postConsoleInput(consoleRequestUrl, api_token, `pip install -r ${web_app.source_directory}/requirements.txt\n`, "Requirements Installed.");
282-
if (isAlembicUsing) {
283-
console.log("Alembic migration starting...");
284-
yield postConsoleInput(consoleRequestUrl, api_token, `alembic upgrade head\n`, "Alembic migrations applied.");
341+
yield postConsoleInput(consoleRequestUrl, api_token, `find ${web_app.source_directory} -type f -name "alembic.ini" -print\n`, "Checking for alembic.ini");
342+
const alembicResponse = yield getLatestConsoleOutput(baseApiUrl, consoleId, api_token, "Alembic check completed");
343+
const alembicCheck = yield parseAndCheckAlembic(alembicResponse, web_app.source_directory);
344+
if (alembicCheck.exists && alembicCheck.path) {
345+
try {
346+
console.log("Alembic configuration found, running migrations...");
347+
yield postConsoleInput(consoleRequestUrl, api_token, `cd $(dirname $(find ${web_app.source_directory} -type f -name "alembic.ini" -print -quit)) && alembic upgrade head\n`, "Checking alembic status");
348+
const alembicUpgradeResponse = yield getLatestConsoleOutput(baseApiUrl, consoleId, api_token, "");
349+
if (alembicUpgradeResponse.output && alembicUpgradeResponse.output.includes("FAILED")) {
350+
console.error("Alembic migration failed. Please check your alembic configuration.");
351+
console.error(alembicUpgradeResponse.output);
352+
}
353+
else {
354+
console.log("Alembic migrations completed successfully");
355+
}
356+
}
357+
catch (error) {
358+
console.error(`Error during alembic migration: ${error.message}`);
359+
}
360+
}
361+
else {
362+
console.log("No Alembic configuration found, skipping migrations");
285363
}
286364
}
287365
catch (error) {

0 commit comments

Comments
 (0)