fix(repo): read the README when the default branch contains a slash

Description

glab repo view reads the README through the project's readme_url, which GitLab builds as <web_url>/-/blob/<default branch>/<README path> (project.rb#L2173-2178), keeping the slash of a branch name such as release/main. getReadmeFile cut the part after /-/blob/ at its first slash to get the ref and the file path (project_view.go#L201-210), so for that branch it asked the repository files API for main/README.md at ref release, at the branch --branch names, or at the current branch inside a clone. The file is not there, and the command failed with 404 Not Found without printing the project. --web and --output json do not read the README and were not affected.

This MR splits the README path at the default branch when the path starts with the default branch followed by a slash, and keeps the first-slash split otherwise, so a README URL that does not start with the default branch is read exactly as before.

Closes #8623 (closed)

Related to #7712 (closed), an earlier report that may be the same defect.

How has this been tested?

Four cases in TestProjectView:

  • "view another project whose default branch contains a slash": default branch release/main and a README in docs/, the subdirectory case !3590 (merged) handled. It asserts both the file path and the ref passed to GetFile.
  • "view the current project whose default branch contains a slash": the same branch inside a clone. It asserts the file path, and that the current branch is still the ref.
  • "view a branch of another project whose default branch contains a slash": --branch release/next against a release/main default branch. It asserts that the file path is still cut at the default branch, and that the ref is the one --branch names.
  • "view another project whose README URL does not start with the default branch": pins the first-slash split that is kept for any other URL.

Without the change to project_view.go the three slash cases fail, because GetFile receives main/docs/README.md or main/README.md as the file path, and the fourth passes; with it, all four pass. Disabling the default branch split, dropping the slash from the prefix, or making the first-slash split return the "invalid README URL" error each make at least one of the cases fail.

End to end, against a stub of the two routes the command calls, serving a project whose default branch is release/main with the readme_url GitLab builds for it: glab repo view OWNER/REPO built from main at a300719a, the commit this branch is based on, exits with 404 Not Found after asking for main/README.md at ref release, and built from this branch it prints the project and its README after asking for README.md at release/main. With --branch release/main the main build asks for main/README.md at release/main and fails the same way, and this branch prints the README.

With Go 1.27.2 and golangci-lint 2.14.0: go test -race ./... passes, golangci-lint run reports 0 issues, golangci-lint fmt --diff, go run ./scripts/comment-overlap -threshold 1.0 -max-findings 0 ./cmd/... ./internal/... and make check-embed check-args are clean, make gen-docs and make generate leave the tree unchanged, and the commit message and the title pass commitlint with scripts/commit-lint/.commitlintrc.js.

Test output without and with the change

Without the change to project_view.go:

--- FAIL: TestProjectView/view_another_project_whose_default_branch_contains_a_slash
        Got: main/docs/README.md (string)
        Want: is equal to docs/README.md (string)
--- FAIL: TestProjectView/view_the_current_project_whose_default_branch_contains_a_slash
        Got: main/README.md (string)
        Want: is equal to README.md (string)
--- FAIL: TestProjectView/view_a_branch_of_another_project_whose_default_branch_contains_a_slash
        Got: main/README.md (string)
        Want: is equal to README.md (string)
--- PASS: TestProjectView/view_another_project_whose_README_URL_does_not_start_with_the_default_branch
FAIL	gitlab.com/gitlab-org/cli/internal/commands/project/view

With it:

--- PASS: TestProjectView/view_another_project_whose_default_branch_contains_a_slash
--- PASS: TestProjectView/view_the_current_project_whose_default_branch_contains_a_slash
--- PASS: TestProjectView/view_a_branch_of_another_project_whose_default_branch_contains_a_slash
--- PASS: TestProjectView/view_another_project_whose_README_URL_does_not_start_with_the_default_branch
ok  	gitlab.com/gitlab-org/cli/internal/commands/project/view

Command: go test -count=1 -v ./internal/commands/project/view/ -run 'TestProjectView|TestGetReadmeFile'.

End-to-end run against a stub of the API

The stub answers GET /api/v4/projects/:id with a project whose default_branch is release/main and whose readme_url is <web_url>/-/blob/release/main/README.md, and the files route with README.md at release/main only, answering 404 for any other ref or path.

glab repo view OWNER/REPO built from main, exit status 1:

ERROR

404 Not Found.
GET /api/v4/projects/OWNER%2FREPO?license=true&with_custom_attributes=true
GET /api/v4/projects/OWNER%2FREPO/repository/files/main%2FREADME%2Emd?ref=release

The same command built from this branch, exit status 0:

name:	Owner / REPO
description:	A project whose default branch is release/main
---
# REPO

The README on release/main.
GET /api/v4/projects/OWNER%2FREPO?license=true&with_custom_attributes=true
GET /api/v4/projects/OWNER%2FREPO/repository/files/README%2Emd?ref=release%2Fmain

With --branch release/main, the main build exits with the same error after asking for files/main%2FREADME%2Emd?ref=release%2Fmain, and this branch prints the same project and README after asking for files/README%2Emd?ref=release%2Fmain.

Edited by José M. Requena Plens

Merge request reports

Loading
Loading