Skip to content

Commit d6aa1af

Browse files
Fix Git commit squash update loop
1 parent ef294c1 commit d6aa1af

5 files changed

Lines changed: 29 additions & 19 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ The app can be started using the following `compose.yml`:
3939
services:
4040
containers-up:
4141
# https://github.com/DigitallyRefined/containers-up/releases
42-
image: ghcr.io/digitallyrefined/containers-up:1.4.3
42+
image: ghcr.io/digitallyrefined/containers-up:1.4.4
4343
restart: unless-stopped
4444
ports:
4545
- 3000:3000
@@ -63,7 +63,7 @@ Optional system wide configuration can be changed by copying `.env.default` to `
6363
services:
6464
containers-up:
6565
# https://github.com/DigitallyRefined/containers-up/releases
66-
image: ghcr.io/digitallyrefined/containers-up:1.4.3
66+
image: ghcr.io/digitallyrefined/containers-up:1.4.4
6767
restart: unless-stopped
6868
volumes:
6969
- ./containers-up/storage:/storage

bun.lock

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

compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
services:
22
containers-up:
33
# https://github.com/DigitallyRefined/containers-up/releases
4-
image: ghcr.io/digitallyrefined/containers-up:1.4.3
4+
image: ghcr.io/digitallyrefined/containers-up:1.4.4
55
container_name: containers-up
66
restart: unless-stopped
77
volumes:

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "containers-up",
3-
"version": "1.4.3",
3+
"version": "1.4.4",
44
"description": "Containers Up! a web based platform designed to manage and update containers",
55
"author": "DigitallyRefined",
66
"license": "ISC",
@@ -54,7 +54,7 @@
5454
"@types/bun": "^1.3.8",
5555
"@types/pino": "^7.0.5",
5656
"@types/pino-pretty": "^5.0.0",
57-
"@types/react": "^19.2.11",
57+
"@types/react": "^19.2.13",
5858
"@types/react-dom": "^19.2.3"
5959
}
6060
}

src/backend/utils/git.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const logger = mainLogger.child({ event });
99
const SQUASH_UPDATE_MESSAGE = process.env.SQUASH_UPDATE_MESSAGE || 'Update dependencies';
1010
const SQUASH_DEPS_DAYS_AGO = Number.parseInt(process.env.SQUASH_DAYS_AGO || '5');
1111
const SQUASH_MAX_UPDATE_COMMITS = Number.parseInt(process.env.SQUASH_MAX_UPDATE_COMMITS || '5');
12+
const GIT_SQUASH_USER =
13+
"GIT_AUTHOR_NAME='Containers Up!' GIT_AUTHOR_EMAIL='260200075+containers-up@users.noreply.github.com'";
1214

1315
const buildMessage = (subject: string, body?: string) => {
1416
const parts = [subject, body].filter(Boolean);
@@ -19,13 +21,15 @@ const gitCommitWithMessage = async (
1921
sshRun: (cmd: string) => Promise<{ stdout: string }>,
2022
message: string,
2123
amend = false,
22-
authorDate?: string
24+
authorDate: string
2325
) => {
2426
const amendFlag = amend ? ' --amend' : '';
25-
const dateFlag = authorDate ? ` --date='${authorDate}'` : '';
27+
const dateFlag = ` --date='${authorDate}'`;
2628
// Use base64 encoding to avoid all shell escaping issues
2729
const base64Message = Buffer.from(message).toString('base64');
28-
await sshRun(`echo '${base64Message}' | base64 -d | git commit${amendFlag}${dateFlag} -F -`);
30+
await sshRun(
31+
`echo '${base64Message}' | base64 -d | env ${GIT_SQUASH_USER} git commit${amendFlag}${dateFlag} -F -`
32+
);
2933
};
3034

3135
const hasUncommittedChanges = async (
@@ -59,9 +63,10 @@ const getCommitMetadata = async (
5963
const updateCurrentCommit = async (
6064
sshRun: (cmd: string) => Promise<{ stdout: string }>,
6165
subject: string,
62-
body: string
66+
body: string,
67+
authorDate?: string
6368
) => {
64-
await gitCommitWithMessage(sshRun, buildMessage(subject, body), true);
69+
await gitCommitWithMessage(sshRun, buildMessage(subject, body), true, authorDate);
6570
};
6671

6772
const squashLastTwoCommits = async (
@@ -113,7 +118,7 @@ const squashOldestTwoCommits = async (
113118
const base64Msg = Buffer.from(squashedMessage).toString('base64');
114119
const newHash = (
115120
await sshRun(
116-
`echo '${base64Msg}' | base64 -d | env GIT_AUTHOR_DATE='${commits[0].authorDate}' git commit-tree ${commits[1].tree} -p HEAD`
121+
`echo '${base64Msg}' | base64 -d | env ${GIT_SQUASH_USER} GIT_AUTHOR_DATE='${commits[0].authorDate}' git commit-tree ${commits[1].tree} -p HEAD`
117122
)
118123
).stdout.trim();
119124
await sshRun(`git reset --hard ${newHash}`);
@@ -126,7 +131,7 @@ const squashOldestTwoCommits = async (
126131
const b64 = Buffer.from(msg).toString('base64');
127132
const hash = (
128133
await sshRun(
129-
`echo '${b64}' | base64 -d | env GIT_AUTHOR_DATE='${commits[i].authorDate}' git commit-tree ${commits[i].tree} -p HEAD`
134+
`echo '${b64}' | base64 -d | env ${GIT_SQUASH_USER} GIT_AUTHOR_DATE='${commits[i].authorDate}' git commit-tree ${commits[i].tree} -p HEAD`
130135
)
131136
).stdout.trim();
132137
await sshRun(`git reset --hard ${hash}`);
@@ -173,12 +178,14 @@ export const squashUpdates = async (
173178
// Get previous commit info
174179
const prevCommit = await getCommitMetadata(sshRun, 1);
175180

176-
const isAutomatedAuthor = /dependabot|renovate/i.test(prevCommit.authorName);
181+
const isAutomatedAuthor = (authorName: string) =>
182+
/dependabot|renovate|containers-up/i.test(authorName);
177183
const X_DAYS_AGO = Date.now() - SQUASH_DEPS_DAYS_AGO * 24 * 60 * 60 * 1000;
178184

179185
if (
180-
isAutomatedAuthor ||
181-
(prevCommit.timestamp > X_DAYS_AGO && prevCommit.subject.includes(SQUASH_UPDATE_MESSAGE))
186+
isAutomatedAuthor(lastCommit.authorName) &&
187+
isAutomatedAuthor(prevCommit.authorName) &&
188+
prevCommit.timestamp > X_DAYS_AGO
182189
) {
183190
// Previous commit is from automated author, squash them together
184191
logger.info(`Squashing last 2 commits together (previous author: ${prevCommit.authorName})`);
@@ -192,9 +199,12 @@ export const squashUpdates = async (
192199
continue;
193200
}
194201

195-
if (!lastCommit.subject.includes(SQUASH_UPDATE_MESSAGE)) {
202+
if (
203+
isAutomatedAuthor(lastCommit.authorName) &&
204+
!lastCommit.subject.includes(SQUASH_UPDATE_MESSAGE)
205+
) {
196206
logger.info('Updating current commit message only (previous is old or not an update commit)');
197-
await updateCurrentCommit(sshRun, lastCommit.subject, lastCommit.body);
207+
await updateCurrentCommit(sshRun, lastCommit.subject, lastCommit.body, lastCommit.authorDate);
198208
}
199209

200210
break;

0 commit comments

Comments
 (0)