/// <summary> /// Creates a repository for the given student, and pushes the non-test files /// from the source project to the new repository. /// </summary> private async Task<CreateAndPushResult> CreateAndPushAsync( Project project, ClassroomMembership student, string webhookUrl, bool overwriteIfSafe, ICollection<GitHubTeam> teams, ICollection<GitHubRepository> repositories, IArchive templateContents) { string orgName = project.Classroom.GitHubOrganization; string repoName = $"{project.Name}_{student.GitHubTeam}"; try { var repository = repositories.SingleOrDefault(repo => repo.Name == repoName); var team = teams.First(teamCandidate => teamCandidate.Name == student.GitHubTeam); bool repositoryAlreadyExisted = (repository != null); if (repositoryAlreadyExisted) { if (!overwriteIfSafe) return CreateAndPushResult.Exists; var commits = await _repoClient.GetAllCommitsAsync(orgName, repoName); if (commits.Count > c_numInitialCommits) return CreateAndPushResult.Exists; } else { repository = await _repoClient.CreateRepositoryAsync ( orgName, repoName, team, overwrite: false ); var staffTeam = GetStaffTeam(project.Classroom, teams); if (staffTeam != null) { await _teamClient.AddRepositoryAsync(orgName, repoName, staffTeam); } } await _repoClient.OverwriteRepositoryAsync ( repository, c_starterCommitMessage, templateContents, entry => project.GetFileType(entry) != FileType.Private, entry => project.GetFileType(entry) == FileType.Immutable ); await _repoClient.EnsurePushWebhookAsync(repository, webhookUrl); return repositoryAlreadyExisted ? CreateAndPushResult.Overwritten : CreateAndPushResult.Created; } catch (Exception ex) { _logger.LogError ( (EventId)0, ex, "Failed to create repository {RepoName} in organization {Org}.", repoName, orgName ); return CreateAndPushResult.Failed; } }
/// <summary> /// Retunrs a list of files in a project repository. /// </summary> public async Task<IList<ProjectRepositoryFile>> GetRepoFileListAsync( Project project) { using ( var repoFiles = await _repoClient.GetRepositoryContentsAsync ( project.Classroom.GitHubOrganization, project.TemplateRepoName, null /*branchName*/, ArchiveStore.Memory ) ) { return repoFiles.Files.Select ( entry => new ProjectRepositoryFile ( project.GetFileType(entry), entry.FullPath ) ).ToList(); } }
/// <summary> /// Writes the contents of a submission to an archive. /// </summary> private async Task WriteSubmissionToArchiveAsync( ZipArchive archive, Project project, ClassroomMembership student, IArchive templateContents, IArchive submissionContents) { var studentFolder = $"EclipseProjects\\{student.GitHubTeam}"; // The project will contain all non-immutable submission files, // plus all immutable and private files from the template project. var projectContents = submissionContents.Files .Where ( entry => project.GetFileType(entry) == FileType.Public ) .Concat ( templateContents.Files.Where ( entry => project.GetFileType(entry) != FileType.Public ) ) .ToList(); foreach (var entry in projectContents) { if (ExcludeEntry(project, entry)) continue; var contents = _transformer.GetFileContents(project, student, entry); var archiveFilePath = entry.FullPath; var archiveFileFolder = archiveFilePath.Contains("/") ? archiveFilePath.Substring(0, archiveFilePath.LastIndexOf("/")) : archiveFilePath; var localFileFolder = $"{studentFolder}\\{archiveFileFolder}"; var fileName = archiveFilePath.Substring(archiveFilePath.LastIndexOf("/") + 1); var localFilePath = $"{localFileFolder}\\{fileName}"; // Add the file to the student project folder. var projectFolderEntry = archive.CreateEntry(localFilePath); using (Stream stream = projectFolderEntry.Open()) { await stream.WriteAsync(contents, offset: 0, count: contents.Length); } // Add the file to the folder containing all files, if applicable. if (fileName.EndsWith(".java") && project.GetFileType(entry) == FileType.Public) { var allFilesEntry = archive.CreateEntry($"AllFiles\\{student.GitHubTeam}-{fileName}"); using (Stream stream = allFilesEntry.Open()) { await stream.WriteAsync(contents, offset: 0, count: contents.Length); } } } }