| 147 |
147 |
|
return Err(AppError::NotFound);
|
| 148 |
148 |
|
}
|
| 149 |
149 |
|
|
| 150 |
|
- |
let owner_dir = std::path::Path::new(git_root).join(&req.owner);
|
| 151 |
|
- |
let repo_dir = owner_dir.join(format!("{}.git", req.repo_name));
|
|
150 |
+ |
let repo_dir = std::path::Path::new(git_root)
|
|
151 |
+ |
.join(&req.owner)
|
|
152 |
+ |
.join(format!("{}.git", req.repo_name));
|
| 152 |
153 |
|
fn io_err(e: std::io::Error) -> AppError { AppError::Internal(e.into()) }
|
| 153 |
154 |
|
|
| 154 |
|
- |
std::fs::create_dir_all(&owner_dir).map_err(io_err)?;
|
| 155 |
|
- |
git2::Repository::init_bare(&repo_dir)
|
| 156 |
|
- |
.map_err(|e| AppError::Internal(e.into()))?;
|
|
155 |
+ |
// Create the bare repo as the git user (the makenotwork service user
|
|
156 |
+ |
// doesn't have write permissions to the git:git owned directory).
|
|
157 |
+ |
let status = std::process::Command::new("sudo")
|
|
158 |
+ |
.args(["-u", "git", "git", "init", "--bare"])
|
|
159 |
+ |
.arg(&repo_dir)
|
|
160 |
+ |
.status()
|
|
161 |
+ |
.map_err(io_err)?;
|
|
162 |
+ |
if !status.success() {
|
|
163 |
+ |
return Err(AppError::Internal(anyhow::anyhow!(
|
|
164 |
+ |
"git init --bare failed for {}",
|
|
165 |
+ |
repo_dir.display()
|
|
166 |
+ |
)));
|
|
167 |
+ |
}
|
| 157 |
168 |
|
|
| 158 |
169 |
|
// Install post-receive hook if build trigger token is configured
|
| 159 |
170 |
|
if let Some(ref token) = state.config.build_trigger_token {
|
| 160 |
171 |
|
let hook_content = crate::build_runner::post_receive_hook(token);
|
| 161 |
|
- |
let hooks_dir = repo_dir.join("hooks");
|
| 162 |
|
- |
std::fs::create_dir_all(&hooks_dir).map_err(io_err)?;
|
| 163 |
|
- |
let hook_path = hooks_dir.join("post-receive");
|
|
172 |
+ |
let hook_path = repo_dir.join("hooks/post-receive");
|
|
173 |
+ |
// Write as root, then chown — hooks dir already exists from git init
|
| 164 |
174 |
|
std::fs::write(&hook_path, &hook_content).map_err(io_err)?;
|
| 165 |
175 |
|
#[cfg(unix)]
|
| 166 |
176 |
|
{
|
| 170 |
180 |
|
std::fs::Permissions::from_mode(0o755),
|
| 171 |
181 |
|
);
|
| 172 |
182 |
|
}
|
| 173 |
|
- |
}
|
| 174 |
|
- |
|
| 175 |
|
- |
// Fix ownership so the git user can write
|
| 176 |
|
- |
let status = std::process::Command::new("chown")
|
| 177 |
|
- |
.args(["-R", "git:git"])
|
| 178 |
|
- |
.arg(&repo_dir)
|
| 179 |
|
- |
.status()
|
| 180 |
|
- |
.map_err(io_err)?;
|
| 181 |
|
- |
if !status.success() {
|
| 182 |
|
- |
return Err(AppError::Internal(anyhow::anyhow!("chown failed on {}", repo_dir.display())));
|
|
183 |
+ |
let _ = std::process::Command::new("chown")
|
|
184 |
+ |
.args(["git:git"])
|
|
185 |
+ |
.arg(&hook_path)
|
|
186 |
+ |
.status();
|
| 183 |
187 |
|
}
|
| 184 |
188 |
|
|
| 185 |
189 |
|
tracing::info!(owner = %req.owner, repo = %req.repo_name, "auto-created bare repository");
|