Skip to content
Open
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 .github/badges/tests.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions code/+matbox/+setup/+internal/+github/repositoryFolderName.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
function folderName = repositoryFolderName(repositoryName, gitRef)
% repositoryFolderName - Name of the folder holding a repository at a git reference
%
% folderName = repositoryFolderName(repositoryName, gitRef) returns
% "<repositoryName>-<gitRef>" with each "/" in gitRef replaced by "-".
% A git reference may contain "/" (as in "release/1.0"), which would
% otherwise make the name a nested path. As observed on github.com, a
% branch archive unpacks to a folder named by the same rule.
%
% Different references can map to the same name, for example
% "release/1.0" and "release-1.0".

arguments
repositoryName (1,1) string
gitRef (1,1) string
end

folderName = repositoryName + "-" + replace(gitRef, "/", "-");
end
11 changes: 7 additions & 4 deletions code/+matbox/+setup/+internal/+pathtool/lookForRepository.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
pathList = strsplit(path, pathsep);

% Candidate folder names, most specific first:
% {repositoryName}-{gitRef} is the folder name of a repository that
% was downloaded as a zip archive (see installGithubRepository).
% repositoryFolderName(repositoryName, gitRef) is the folder name of a
% repository that was downloaded as a zip archive (see
% installGithubRepository).
% {repositoryName} is the folder name of a repository cloned with git.
% Each candidate is matched both as the last folder of a path entry
% ("$") and as a parent folder of a path entry (filesep).
archiveFolderName = ...
matbox.setup.internal.github.repositoryFolderName(repositoryName, gitRef);
candidateFolderNames = [ ...
sprintf("%s-%s", repositoryName, gitRef), ...
sprintf("%s-%s", repositoryName, gitRef), ...
archiveFolderName, ...
archiveFolderName, ...
string(repositoryName), ...
string(repositoryName)];
candidateSuffixes = ["$", filesep, "$", filesep];
Expand Down
11 changes: 6 additions & 5 deletions code/+matbox/+setup/+internal/installGithubRepository.m
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,15 @@
% scheme; as observed on github.com, a leading "v" is dropped from tag
% names (v1.0.0 unpacks to <repo>-1.0.0) and an abbreviated commit SHA is
% expanded to the full hash, while branch archives unpack to
% <repo>-<branch>. Renaming to the reference exactly as written in the
% requirement makes the folder name predictable regardless of how GitHub
% names the archive, so that lookForRepository recognises the
% installation on later runs instead of downloading again.
% <repo>-<branch> with each "/" replaced by "-". Renaming to the name
% given by repositoryFolderName, which is derived from the reference as
% written in the requirement, makes the folder name predictable
% regardless of how GitHub names the archive, so that lookForRepository
% recognises the installation on later runs instead of downloading again.

[parentFolder, folderName, folderNameSuffix] = fileparts(repoFolder);
actualName = strcat(folderName, folderNameSuffix); % fileparts splits names like "repo-1.0.0" at the last dot
expectedName = sprintf('%s-%s', repositoryName, gitRef);
expectedName = matbox.setup.internal.github.repositoryFolderName(repositoryName, gitRef);

% Compare case-insensitively: the archive uses the repository's canonical
% casing, which may differ from the casing in the requirement URL.
Expand Down
38 changes: 33 additions & 5 deletions tools/tests/+matboxtools/+unittest/GithubReferenceTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
%
% A GitHub requirement may pin a branch name, tag name, or commit SHA
% using the "<url>@<ref>" form. These tests cover parsing the reference,
% locating an installed copy on the search path, and installing from
% GitHub. The install tests require network access.
% naming the installation folder, locating an installed copy on the
% search path, and installing from GitHub. The install tests require
% network access.

properties (Constant)
RepositoryUrl = "https://github.com/ehennestad/StructEditor"
Expand All @@ -15,9 +16,15 @@
% exercise the rename to "<repo>-<ref>" 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.
% A branch name in the hierarchical form and the folder name it
% maps to. Used only by tests that need no network access, so the
% branch need not exist in the test repository.
HierarchicalBranchName = "release/1.0"
HierarchicalBranchFolderName = "StructEditor-release-1.0"
% A branch in the test repository whose name contains "/". As
% observed on github.com, its archive folder is named
% "StructEditor-codex-nansen-compatibility-contract".
ExistingHierarchicalBranchName = "codex/nansen-compatibility-contract"
end

methods (TestMethodSetup)
Expand Down Expand Up @@ -52,6 +59,20 @@ function testParseUrlWithCommitReference(testCase)
testCase.verifyEqual(gitRef, testCase.CommitSha)
end

function testRepositoryFolderNameReplacesSlashes(testCase)
folderName = matbox.setup.internal.github.repositoryFolderName( ...
testCase.RepositoryName, testCase.HierarchicalBranchName);
testCase.verifyEqual(folderName, testCase.HierarchicalBranchFolderName)
end

function testLookForRepositoryFindsHierarchicalBranchFolder(testCase)
folderPath = testCase.createRepositoryFolder(testCase.HierarchicalBranchFolderName);
[exists, repositoryPath] = matbox.setup.internal.pathtool.lookForRepository( ...
testCase.RepositoryName, testCase.HierarchicalBranchName);
testCase.verifyTrue(exists)
testCase.verifyEqual(repositoryPath, folderPath)
end

function testParseUrlWithSlashInReference(testCase)
[~, repositoryName, gitRef] = matbox.setup.internal.github.parseRepositoryURL( ...
testCase.RepositoryUrl + "@" + testCase.HierarchicalBranchName);
Expand Down Expand Up @@ -113,6 +134,10 @@ function testInstallTagPinnedRequirement(testCase)
function testInstallCommitPinnedRequirement(testCase)
testCase.verifyInstallAndReinstall(testCase.CommitSha)
end

function testInstallHierarchicalBranchPinnedRequirement(testCase)
testCase.verifyInstallAndReinstall(testCase.ExistingHierarchicalBranchName)
end
end

methods (Access = private)
Expand All @@ -128,7 +153,10 @@ function testInstallCommitPinnedRequirement(testCase)

function verifyInstallAndReinstall(testCase, gitRef)
sourceUri = testCase.RepositoryUrl + "@" + gitRef;
expectedFolder = string(fullfile(pwd, testCase.RepositoryName + "-" + gitRef));
% The installation folder sits directly in the installation
% location, with each "/" of the reference replaced by "-".
expectedFolder = string(fullfile(pwd, ...
testCase.RepositoryName + "-" + replace(gitRef, "/", "-")));

installResult = matbox.setup.installFromSourceUri(sourceUri, ...
"InstallationLocation", pwd, "Verbose", false);
Expand Down