Skip to content

Commit

Permalink
Development: Improve git URI handling for LocalVC (#8484)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hialus authored Apr 28, 2024
1 parent 4b66931 commit ad88eca
Show file tree
Hide file tree
Showing 10 changed files with 495 additions and 75 deletions.
95 changes: 86 additions & 9 deletions src/main/java/de/tum/in/www1/artemis/domain/VcsRepositoryUri.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,73 @@
import java.net.URISyntaxException;
import java.util.Objects;

/**
* Represents a Version Control System (VCS) repository URI with capabilities to manipulate and extract information from it.
* This class supports handling both local file references and remote repository URIs.
*/
public class VcsRepositoryUri {

/** The username associated with the VCS repository URI, if applicable. */
protected String username;

/** The URI representing either a local file path or a remote repository URL. */
protected URI uri;

/**
* Default constructor, intended for internal use only to prevent compile errors.
* This constructor is protected to discourage its use as it creates an uninitialized object.
*/
protected VcsRepositoryUri() {
// NOTE: this constructor should not be used and only exists to prevent compile errors
}

// Create the url from a uriSpecString, e.g. https://username@artemistest2gitlab.ase.in.tum.de/FTCSCAGRADING1/ftcscagrading1-username
/**
* Initializes a new instance of the {@link VcsRepositoryUri} class based on a specified URI string.
* The URI string should represent a complete URI to a VCS repository, e.g. https://username@artemistest2gitlab.ase.in.tum.de/FTCSCAGRADING1/ftcscagrading1-username
*
* @param uriSpecString The URI string to be parsed into a URI.
* @throws URISyntaxException If the provided string does not form a valid URI.
*/
public VcsRepositoryUri(String uriSpecString) throws URISyntaxException {
this.uri = new URI(uriSpecString);
}

// Create the url from a file reference, e.g. C:/Users/Admin/AppData/Local/Temp/studentOriginRepo1644180397872264950
/**
* Initializes a new instance of the {@link VcsRepositoryUri} class from a file reference, e.g. C:/Users/Admin/AppData/Local/Temp/studentOriginRepo1644180397872264950
* The file's URI is extracted and stored.
*
* @param file The file from which the URI will be created.
*/
public VcsRepositoryUri(java.io.File file) {
this.uri = file.toURI();
}

/**
* Associates a username with the current VCS repository URI and returns the instance for chaining.
*
* @param username The username to be associated with the URI.
* @return The instance of {@link VcsRepositoryUri} with the username set.
*/
public VcsRepositoryUri withUser(final String username) {
this.username = username;
return this;
}

/**
* Returns the URI associated with this VCS repository.
*
* @return The URI of the VCS repository.
*/
public URI getURI() {
return this.uri;
}

/**
* Compares this instance with another object for equality, considering both the username and the URI.
* This method also supports comparisons with subclasses of {@link VcsRepositoryUri}.
*
* @param obj The object to compare with this instance.
* @return true if the provided object is equivalent to this instance; false otherwise.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
Expand Down Expand Up @@ -62,7 +100,8 @@ public String toString() {
}

/**
* Generates the unique local folder name for a given file or remote repository URI.
* Generates a folder name from the URI to uniquely represent the repository locally.
* It takes the last path segment of file URIs and the full path for remote repository URIs, excluding any .git suffix.
* For file URIs, we take the last element of the path, which should be unique
* For URLs pointing to remote git repositories, we use the whole path
* <p>
Expand All @@ -71,7 +110,7 @@ public String toString() {
* file:C:/Users/Admin/AppData/Local/Temp/studentOriginRepo1644180397872264950 --> studentOriginRepo1644180397872264950
* file:/var/folders/vc/sk85td_s54v7w9tjq07b0_q80000gn/T/studentTeamOriginRepo420037178325056205/ --> studentTeamOriginRepo420037178325056205
*
* @return the folderName as a string.
* @return A string representing the folder name derived from the URI.
*/
public String folderNameForRepositoryUri() {
if ("file".equals(uri.getScheme())) {
Expand All @@ -91,22 +130,60 @@ public String folderNameForRepositoryUri() {
}

/**
* Retrieves the repository name without the project key and the optional practice prefix from the URI.
* Extracts and returns the repository name from the URI, removing any leading project key and optional "practice" prefix.
* This method is useful for isolating the pure repository name in contexts where the higher-level organizational
* identifiers (like project keys) are not needed.
* <p>
* The method performs the following transformations:
* <ul>
* <li>Converts the full repository URI path into its base name with the ".git" suffix removed.</li>
* <li>Strips out the leading project key followed by a dash ("-").</li>
* <li>Removes any "practice-" prefix used for practice repositories.</li>
* </ul>
* <p>
* Examples:
* http://localhost:8080/git/GREAT/great-artemis_admin.git --> artemis_admin
* http://localhost:8080/git/GREAT/great-practice-artemis_admin.git --> artemis_admin
* <ul>
* <li>http://localhost:8080/git/GREAT/great-artemis_admin.git --> artemis_admin</li>
* <li>http://localhost:8080/git/GREAT/great-practice-artemis_admin.git --> artemis_admin</li>
* </ul>
*
* @return the repository name without the project key and the optional practice prefix.
* @return The repository name without the project key and the practice prefix, in lowercase.
*/
public String repositoryNameWithoutProjectKey() {
return repositorySlug().toLowerCase().replace(projectKey().toLowerCase() + "-", "").replace("practice-", "");
}

/**
* Retrieves the last part of the URI path, typically representing the repository slug or name.
* This slug usually corresponds to the actual name of the repository in the version control system, without any path
* prefixes or the ".git" file extension. This method is often used as a helper for other methods that need to process
* or display the repository name.
* <p>
* Example:
* <ul>
* <li>From the URI "http://localhost:8080/git/GREAT/great-artemis_admin.git", it extracts "great-artemis_admin".</li>
* </ul>
*
* @return The repository slug derived from the URI's path.
*/
public String repositorySlug() {
return this.uri.getPath().substring(this.uri.getPath().lastIndexOf('/') + 1).replace(".git", "");
}

/**
* Extracts the project key from a VCS repository URI. The project key is assumed to be the second-to-last
* segment of the path in the URI, which typically identifies the organizational or project-level identifier under
* which the repository is categorized in the VCS.
* <p>
* This method is particularly useful when handling URIs where repository access is structured by project keys.
* <p>
* Example:
* <ul>
* <li>From the URI "http://localhost:8080/git/GREAT/great-artemis_admin.git", it extracts "GREAT".</li>
* </ul>
*
* @return The project key in lowercase, as found in the URI's path.
*/
private String projectKey() {
return this.uri.getPath().substring(this.uri.getPath().lastIndexOf('/', this.uri.getPath().lastIndexOf('/') - 1) + 1, this.uri.getPath().lastIndexOf('/')).toLowerCase();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ private String getGitUriAsString(VcsRepositoryUri vcsRepositoryUri) throws URISy
private URI getGitUri(VcsRepositoryUri vcsRepositoryUri) throws URISyntaxException {
if (profileService.isLocalVcsCiActive()) {
// Create less generic LocalVCRepositoryUri out of VcsRepositoryUri.
LocalVCRepositoryUri localVCRepositoryUri = new LocalVCRepositoryUri(vcsRepositoryUri.toString(), gitUrl);
LocalVCRepositoryUri localVCRepositoryUri = new LocalVCRepositoryUri(vcsRepositoryUri.toString());
String localVCBasePath = environment.getProperty("artemis.version-control.local-vcs-repo-path");
return localVCRepositoryUri.getLocalRepositoryPath(localVCBasePath).toUri();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ public LocalCIBuildResult runBuildJob(LocalCIBuildJobQueueItem buildJob, String
|| buildJob.repositoryInfo().triggeredByPushTo() == RepositoryType.AUXILIARY;

// get the local repository paths for assignment, tests, auxiliary and solution
LocalVCRepositoryUri assignmentRepoUri = new LocalVCRepositoryUri(buildJob.repositoryInfo().assignmentRepositoryUri(), localVCBaseUrl);
LocalVCRepositoryUri testsRepoUri = new LocalVCRepositoryUri(buildJob.repositoryInfo().testRepositoryUri(), localVCBaseUrl);
LocalVCRepositoryUri assignmentRepoUri = new LocalVCRepositoryUri(buildJob.repositoryInfo().assignmentRepositoryUri());
LocalVCRepositoryUri testsRepoUri = new LocalVCRepositoryUri(buildJob.repositoryInfo().testRepositoryUri());

// retrieve last commit hash from repositories
String assignmentCommitHash = buildJob.buildConfig().commitHash();
Expand Down Expand Up @@ -174,7 +174,7 @@ public LocalCIBuildResult runBuildJob(LocalCIBuildJobQueueItem buildJob, String
LocalVCRepositoryUri solutionRepoUri = null;
Path solutionRepositoryPath = null;
if (buildJob.repositoryInfo().solutionRepositoryUri() != null) {
solutionRepoUri = new LocalVCRepositoryUri(buildJob.repositoryInfo().solutionRepositoryUri(), localVCBaseUrl);
solutionRepoUri = new LocalVCRepositoryUri(buildJob.repositoryInfo().solutionRepositoryUri());
// In case we have the same repository for assignment and solution, we can use the same path
if (Objects.equals(solutionRepoUri.repositorySlug(), assignmentRepoUri.repositorySlug())) {
solutionRepositoryPath = assignmentRepositoryPath;
Expand All @@ -190,7 +190,7 @@ public LocalCIBuildResult runBuildJob(LocalCIBuildJobQueueItem buildJob, String

int index = 0;
for (String auxiliaryRepositoryUri : auxiliaryRepositoryUriList) {
auxiliaryRepositoriesUris[index] = new LocalVCRepositoryUri(auxiliaryRepositoryUri, localVCBaseUrl);
auxiliaryRepositoriesUris[index] = new LocalVCRepositoryUri(auxiliaryRepositoryUri);
auxiliaryRepositoriesPaths[index] = cloneRepository(auxiliaryRepositoriesUris[index], assignmentCommitHash, false, buildJob.id());
index++;
}
Expand Down
Loading

0 comments on commit ad88eca

Please sign in to comment.