Anchor patch hunks as git apply does, refuse patches touching non-100644 files by their real mode, survive bare-CR context lines (issue 1604 review)
mesh/merge-gate head 324e331184da merged into trunk 0f2cee1bea4e — pass: builds gitea → novox; no bus step; every machine composes with the change as it di…
mesh/repo-check head 324e331184da merged into trunk 0f2cee1bea4e — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery covered: a later merge that contains it was delivered: novox/mesh-catalog@e023f69989ab (merged as b5dbfbb7 into main, walk plan-17925769516…
mesh/merge-gate head 324e331184da merged into trunk 0f2cee1bea4e — pass: builds gitea → novox; no bus step; every machine composes with the change as it di…
mesh/repo-check head 324e331184da merged into trunk 0f2cee1bea4e — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery covered: a later merge that contains it was delivered: novox/mesh-catalog@e023f69989ab (merged as b5dbfbb7 into main, walk plan-17925769516…
This commit is contained in:
@@ -340,7 +340,14 @@ func commit(ctx context.Context, f *Forge, a CommitAsk) (*Committed, error) {
|
||||
forgeApplied = true
|
||||
case errors.As(err, &status) && status.Status >= 500:
|
||||
delete(on, "content")
|
||||
read := func(p string) ([]byte, bool, error) { return f.contentAt(ctx, repo, p, ref) }
|
||||
read := func(p string) ([]byte, string, bool, error) {
|
||||
b, ok, err := f.contentAt(ctx, repo, p, ref)
|
||||
if err != nil || !ok {
|
||||
return nil, "", false, err
|
||||
}
|
||||
mode, err := f.modeAt(ctx, repo, ref, p)
|
||||
return b, mode, true, err
|
||||
}
|
||||
var perr error
|
||||
if files, perr = patchAsFiles(a.Patch, read); perr != nil {
|
||||
return nil, fmt.Errorf("the forge did not take the patch: %w; the tool could not apply it itself: %v", err, perr)
|
||||
@@ -545,3 +552,43 @@ func (f *Forge) contentAt(ctx context.Context, repo, path, ref string) ([]byte,
|
||||
}
|
||||
return raw, true, nil
|
||||
}
|
||||
|
||||
// modeAt is the git mode of a file at a commit, read through the git trees API: the contents API carries none.
|
||||
func (f *Forge) modeAt(ctx context.Context, repo, ref, path string) (string, error) {
|
||||
parts := strings.Split(path, "/")
|
||||
tree := ref
|
||||
for depth, name := range parts {
|
||||
found := false
|
||||
for page := 1; ; page++ {
|
||||
var got struct {
|
||||
Tree []struct {
|
||||
Path string `json:"path"`
|
||||
Mode string `json:"mode"`
|
||||
Type string `json:"type"`
|
||||
SHA string `json:"sha"`
|
||||
} `json:"tree"`
|
||||
Total int `json:"total_count"`
|
||||
}
|
||||
if err := f.GetJSON(ctx, fmt.Sprintf("%s/git/trees/%s?per_page=1000&page=%d", repo, url.PathEscape(tree), page), &got); err != nil {
|
||||
return "", fmt.Errorf("the mode of %s could not be read: %w", path, err)
|
||||
}
|
||||
for _, e := range got.Tree {
|
||||
if e.Path != name {
|
||||
continue
|
||||
}
|
||||
if depth == len(parts)-1 {
|
||||
return e.Mode, nil
|
||||
}
|
||||
tree, found = e.SHA, true
|
||||
break
|
||||
}
|
||||
if found || len(got.Tree) == 0 || page*1000 >= got.Total {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found && depth < len(parts)-1 {
|
||||
return "", fmt.Errorf("the mode of %s could not be read: %s is not a folder at %s", path, name, short(ref))
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("the mode of %s could not be read: not in the tree of %s", path, short(ref))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user