Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/lib/src/core/templates-entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
renderEntrypointZshShell,
renderEntrypointZshUserRc
} from "./templates-entrypoint/base.js"
import { renderEntrypointDnsRepair } from "./templates-entrypoint/dns-repair.js"
import { renderEntrypointClaudeConfig } from "./templates-entrypoint/claude.js"
import {
renderEntrypointAgentsNotice,
Expand All @@ -20,6 +19,7 @@ import {
renderEntrypointCodexSharedAuth,
renderEntrypointMcpPlaywright
} from "./templates-entrypoint/codex.js"
import { renderEntrypointDnsRepair } from "./templates-entrypoint/dns-repair.js"
import { renderEntrypointGeminiConfig } from "./templates-entrypoint/gemini.js"
import { renderEntrypointGitConfig, renderEntrypointGitHooks } from "./templates-entrypoint/git.js"
import { renderEntrypointDockerGitBootstrap } from "./templates-entrypoint/nested-docker-git.js"
Expand Down
4 changes: 2 additions & 2 deletions packages/lib/src/core/templates-entrypoint/dns-repair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// INVARIANT: after execution, at least one nameserver in /etc/resolv.conf resolves external domains
// COMPLEXITY: O(1) per probe attempt, O(max_attempts) worst case
export const renderEntrypointDnsRepair = (): string =>
`# 0) Ensure DNS resolution works; repair /etc/resolv.conf if Docker DNS is broken
String.raw`# 0) Ensure DNS resolution works; repair /etc/resolv.conf if Docker DNS is broken
docker_git_repair_dns() {
local test_domain="github.com"
local resolv="/etc/resolv.conf"
Expand All @@ -32,7 +32,7 @@ docker_git_repair_dns() {

if [[ "$has_external" -eq 0 ]]; then
for ns in $fallback_dns; do
printf "nameserver %s\\n" "$ns" >> "$resolv"
printf "nameserver %s\n" "$ns" >> "$resolv"
done
echo "[dns-repair] appended fallback nameservers to $resolv"
fi
Expand Down
2 changes: 1 addition & 1 deletion packages/lib/src/shell/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import type * as FileSystem from "@effect/platform/FileSystem"
import type * as Path from "@effect/platform/Path"
import { Effect, Match } from "effect"

import { type TemplateConfig } from "../core/domain.js"
import { dockerGitScriptNames } from "../core/docker-git-scripts.js"
import { type TemplateConfig } from "../core/domain.js"
import { resolveComposeResourceLimits, withDefaultResourceLimitIntent } from "../core/resource-limits.js"
import { type FileSpec, planFiles } from "../core/templates.js"
import { FileExistsError } from "./errors.js"
Expand Down
4 changes: 3 additions & 1 deletion packages/lib/src/usecases/projects-apply-all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export const applyAllDockerGitProjects: Effect.Effect<
runDockerComposeUpWithPortCheck(status.projectDir).pipe(
Effect.catchTag("DockerCommandError", (error: DockerCommandError) =>
Effect.logWarning(
`apply failed for ${status.projectDir}: ${renderError(error)}. Check the project docker-compose config (e.g. env files for merge conflicts, port conflicts in docker-compose.yml config) and retry.`
`apply failed for ${status.projectDir}: ${
renderError(error)
}. Check the project docker-compose config (e.g. env files for merge conflicts, port conflicts in docker-compose.yml config) and retry.`
)),
Effect.catchTag("ConfigNotFoundError", (error) =>
Effect.logWarning(
Expand Down
2 changes: 1 addition & 1 deletion packages/lib/src/usecases/projects.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { applyAllDockerGitProjects } from "./projects-apply-all.js"
export {
buildSshCommand,
loadProjectItem,
Expand All @@ -7,7 +8,6 @@ export {
type ProjectLoadError,
type ProjectStatus
} from "./projects-core.js"
export { applyAllDockerGitProjects } from "./projects-apply-all.js"
export { deleteDockerGitProject } from "./projects-delete.js"
export { downAllDockerGitProjects } from "./projects-down.js"
export { listProjectItems, listProjects, listProjectSummaries, listRunningProjectItems } from "./projects-list.js"
Expand Down
26 changes: 23 additions & 3 deletions packages/lib/src/usecases/state-repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,15 @@ export const autoPullState: Effect.Effect<void, never, StateRepoEnv> = Effect.ge
if (!enabled) {
return
}
yield* _(statePullInternal(root))
// CHANGE: abort any in-progress rebase if pull fails to prevent conflict markers
// WHY: if git pull --rebase fails (e.g. due to merge commits), git leaves the repo
// in a conflicted state with conflict markers; rebase --abort restores clean state
// PURITY: SHELL
yield* _(
statePullInternal(root).pipe(
Effect.tapError(() => git(root, ["rebase", "--abort"], gitBaseEnv).pipe(Effect.orElse(() => Effect.void)))
)
)
}).pipe(
Effect.matchEffect({
onFailure: (error) => Effect.logWarning(`State auto-pull failed: ${String(error)}`),
Expand All @@ -187,9 +195,21 @@ const statePullInternal = (
)
const originUrl = yield* _(normalizeOriginUrlIfNeeded(root, rawOriginUrl))
const token = yield* _(resolveGithubToken(fs, path, root))
// CHANGE: resolve current branch and pass origin <branch> explicitly
// WHY: bare `git pull --rebase` can fail or pull the wrong branch in some git configurations
// QUOTE(ТЗ): "Сделай что бы правильные параметры передавались"
// REF: issue-181
// PURITY: SHELL
const branchRaw = yield* _(
gitCapture(root, ["rev-parse", "--abbrev-ref", "HEAD"], gitBaseEnv).pipe(
Effect.map((value) => value.trim()),
Effect.orElse(() => Effect.succeed("main"))
)
)
const branch = branchRaw === "HEAD" ? "main" : branchRaw
const effect = token && token.length > 0 && isGithubHttpsRemote(originUrl)
? withGithubAskpassEnv(token, (env) => git(root, ["pull", "--rebase"], env))
: git(root, ["pull", "--rebase"], gitBaseEnv)
? withGithubAskpassEnv(token, (env) => git(root, ["pull", "--rebase", "origin", branch], env))
: git(root, ["pull", "--rebase", "origin", branch], gitBaseEnv)
yield* _(effect)
}).pipe(Effect.asVoid)

Expand Down
17 changes: 15 additions & 2 deletions packages/lib/src/usecases/state-repo/pull-push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,22 @@ export const statePull: Effect.Effect<
return
}
const auth = yield* _(resolveStateGithubContext(fs, path, root))
// CHANGE: resolve current branch and pass origin <branch> explicitly
// WHY: bare `git pull --rebase` can fail or pull the wrong branch in some git configurations
// QUOTE(ТЗ): "Сделай что бы правильные параметры передавались"
// REF: issue-181
// PURITY: SHELL
const branchRaw = yield* _(
pipe(
gitCapture(root, ["rev-parse", "--abbrev-ref", "HEAD"], gitBaseEnv),
Effect.map((value) => value.trim()),
Effect.orElse(() => Effect.succeed("main"))
)
)
const branch = branchRaw === "HEAD" ? "main" : branchRaw
const effect = auth.token && auth.token.length > 0 && isGithubHttpsRemote(auth.originUrl)
? withGithubAskpassEnv(auth.token, (env) => git(root, ["pull", "--rebase"], env))
: git(root, ["pull", "--rebase"], gitBaseEnv)
? withGithubAskpassEnv(auth.token, (env) => git(root, ["pull", "--rebase", "origin", branch], env))
: git(root, ["pull", "--rebase", "origin", branch], gitBaseEnv)
yield* _(withGithubAuthHintOnFailure(effect, auth.authHintNeeded))
}).pipe(Effect.asVoid)

Expand Down