From 1366b20bb38d423485a052c6b07e9a089ee0d0ca Mon Sep 17 00:00:00 2001 From: ehennestad Date: Thu, 15 Oct 2026 23:34:45 +0200 Subject: [PATCH 1/2] fix: keep "/" in GitHub git references parseRepositoryURL read the reference from the path segment that holds the repository name, so a branch such as "release/1.0" came back as "release". vendorPackage then asked GitHub for the wrong reference. The reference is now everything after the first "@", up to the end of the path. git allows both "/" and "@" in reference names. installFromSourceUri had its own parser for the same URL form. It split the whole URI at every "@", so "a@b" came back as "a", and it passed URLs such as ".../tree/main" on unchanged, which made the archive URL invalid. It now calls parseRepositoryURL and rebuilds the repository URL from the owner and the repository name. A URL with path segments after the repository name and no "@" is now an error (MATBOX:GitHub:InvalidRepositoryURL). Ignoring the segments would install the default branch instead of the branch in the URL. GitHub resolves a reference containing "/" in both the commits API (repos///commits/) and the archive download (/archive/.zip), so the URLs built from the reference are unchanged. Co-Authored-By: Claude Opus 5.5 --- .../+internal/+github/parseRepositoryURL.m | 19 +++++++--- code/+matbox/+setup/installFromSourceUri.m | 14 ++----- .../+unittest/GithubReferenceTest.m | 38 +++++++++++++++++++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/code/+matbox/+setup/+internal/+github/parseRepositoryURL.m b/code/+matbox/+setup/+internal/+github/parseRepositoryURL.m index 5cff13c..6e48bff 100644 --- a/code/+matbox/+setup/+internal/+github/parseRepositoryURL.m +++ b/code/+matbox/+setup/+internal/+github/parseRepositoryURL.m @@ -4,7 +4,10 @@ % [owner, repositoryName, gitRef] = parseRepositoryURL(repoUrl) splits a % GitHub repository URL of the form https://github.com//[@ref] % into its parts. gitRef is the branch name, tag name, or commit SHA -% following "@", or a missing string when the URL has no "@" suffix. +% following the first "@", including any "/" in it (as in +% "release/1.0"), or a missing string when the URL has no "@" suffix. +% A URL with path segments after the repository name and no "@", such +% as https://github.com///tree/, is an error. arguments repoUrl (1,1) matlab.net.URI @@ -21,11 +24,17 @@ owner = pathNames(1); repositoryName = pathNames(2); + % A git reference may contain "/" and "@", so the reference is + % everything after the first "@", up to the end of the path. gitRef = string(missing); - if contains(repositoryName, '@') - splitName = split(repositoryName, '@'); - repositoryName = splitName(1); - gitRef = splitName(2); + if contains(repositoryName, "@") + gitRef = strjoin([extractAfter(repositoryName, "@"), pathNames(3:end)], "/"); + repositoryName = extractBefore(repositoryName, "@"); + elseif numel(pathNames) > 2 + error("MATBOX:GitHub:InvalidRepositoryURL", ... + "The repository URL ""%s"" has path segments after the repository name. " + ... + "Give a branch, tag or commit as https://github.com//@.", ... + string(repoUrl)) end if nargout < 3 diff --git a/code/+matbox/+setup/installFromSourceUri.m b/code/+matbox/+setup/installFromSourceUri.m index 807cdb5..6eb2bc6 100644 --- a/code/+matbox/+setup/installFromSourceUri.m +++ b/code/+matbox/+setup/installFromSourceUri.m @@ -50,7 +50,9 @@ "ToolboxIdentifier", packageUuid); elseif startsWith(sourceUri, "https://github.com/") - [repoUrl, gitRef] = parseGitHubSourceUri(sourceUri); + [ownerName, repositoryName, gitRef] = ... + matbox.setup.internal.github.parseRepositoryURL(sourceUri); + repoUrl = "https://github.com/" + ownerName + "/" + repositoryName; repoTargetFolder = matbox.setup.internal.installGithubRepository( ... repoUrl, ... gitRef, ... @@ -109,13 +111,3 @@ version, splitUri{2}, strjoin(" - " + string(packageInfo.versions), newline)); end end - -function [repoUrl, gitRef] = parseGitHubSourceUri(repoUrl) -% parseGitHubSourceUri - Extract the git reference (branch, tag or commit) if present - gitRef = string(missing); - if contains(repoUrl, '@') - splitUrl = strsplit(repoUrl, '@'); - repoUrl = splitUrl{1}; - gitRef = splitUrl{2}; - end -end diff --git a/tools/tests/+matboxtools/+unittest/GithubReferenceTest.m b/tools/tests/+matboxtools/+unittest/GithubReferenceTest.m index 7601e42..69a1a5c 100644 --- a/tools/tests/+matboxtools/+unittest/GithubReferenceTest.m +++ b/tools/tests/+matboxtools/+unittest/GithubReferenceTest.m @@ -15,6 +15,9 @@ % exercise the rename to "-" done by installGithubRepository. TagName = "v0.1.0" CommitSha = "4e8eaa6" + % A branch name in the hierarchical form, used only by parsing tests, + % so it need not exist in the test repository. + HierarchicalBranchName = "release/1.0" end methods (TestMethodSetup) @@ -49,6 +52,41 @@ function testParseUrlWithCommitReference(testCase) testCase.verifyEqual(gitRef, testCase.CommitSha) end + function testParseUrlWithSlashInReference(testCase) + [~, repositoryName, gitRef] = matbox.setup.internal.github.parseRepositoryURL( ... + testCase.RepositoryUrl + "@" + testCase.HierarchicalBranchName); + testCase.verifyEqual(repositoryName, testCase.RepositoryName) + testCase.verifyEqual(gitRef, testCase.HierarchicalBranchName) + end + + function testParseUrlWithTrailingSlashAfterReference(testCase) + [~, ~, gitRef] = matbox.setup.internal.github.parseRepositoryURL( ... + testCase.RepositoryUrl + "@" + testCase.HierarchicalBranchName + "/"); + testCase.verifyEqual(gitRef, testCase.HierarchicalBranchName) + end + + function testParseUrlWithAtSignInReference(testCase) + % Only the first "@" separates the repository name from the + % reference; git allows "@" inside a reference name. + [~, repositoryName, gitRef] = matbox.setup.internal.github.parseRepositoryURL( ... + testCase.RepositoryUrl + "@fix@2"); + testCase.verifyEqual(repositoryName, testCase.RepositoryName) + testCase.verifyEqual(gitRef, "fix@2") + end + + function testParseUrlWithPathAfterRepositoryNameErrors(testCase) + testCase.verifyError(@() matbox.setup.internal.github.parseRepositoryURL( ... + testCase.RepositoryUrl + "/tree/main"), "MATBOX:GitHub:InvalidRepositoryURL") + end + + function testInstallWithPathAfterRepositoryNameErrors(testCase) + % The URI is parsed before any request to GitHub, so this test + % needs no network access. + testCase.verifyError(@() matbox.setup.installFromSourceUri( ... + testCase.RepositoryUrl + "/tree/main", "InstallationLocation", pwd), ... + "MATBOX:GitHub:InvalidRepositoryURL") + end + function testLookForRepositoryFindsTagFolder(testCase) folderPath = testCase.createRepositoryFolder( ... testCase.RepositoryName + "-" + testCase.TagName); From ab61a13ff08e12d043898d14903b37796c0bfe3c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 15 Oct 2026 21:40:08 +0000 Subject: [PATCH 2/2] Update GitHub badges [skip ci] --- .github/badges/tests.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/badges/tests.svg b/.github/badges/tests.svg index 828f2d7..8306689 100644 --- a/.github/badges/tests.svg +++ b/.github/badges/tests.svg @@ -1 +1 @@ -tests: 83 passedtests83 passed +tests: 88 passedtests88 passed