Browse Source

created initial build command

pull/5418/head
İsmail ÇAĞDAŞ 6 years ago
parent
commit
805199acc9
  1. 1
      framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj
  2. 1
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
  3. 188
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DefaultChangedProjectFinder.cs
  4. 72
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DefaultDotNetProjectBuilder.cs
  5. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DotNetProjectBuildConfig.cs
  6. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DotNetProjectBuildStatus.cs
  7. 93
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DotNetProjectDependencyFiller.cs
  8. 22
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DotNetProjectInfo.cs
  9. 91
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/GitRepository.cs
  10. 88
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/GitRepositoryBuildStatus.cs
  11. 69
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IBuildArgsReader.cs
  12. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IChangedProjectFinder.cs
  13. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IDotNetProjectBuilder.cs
  14. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IDotNetProjectDependencyFiller.cs
  15. 58
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IRepositoryBuildStatusStore.cs
  16. 180
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/BuildCommand.cs

1
framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj

@ -22,6 +22,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" />
<PackageReference Include="Polly" Version="7.2.1" /> <PackageReference Include="Polly" Version="7.2.1" />
<PackageReference Include="Polly.Extensions.Http" Version="3.0.0" /> <PackageReference Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageReference Include="LibGit2Sharp" Version="0.26.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

1
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs

@ -34,6 +34,7 @@ namespace Volo.Abp.Cli
options.Commands["switch-to-stable"] = typeof(SwitchToStableCommand); options.Commands["switch-to-stable"] = typeof(SwitchToStableCommand);
options.Commands["switch-to-nightly"] = typeof(SwitchToNightlyCommand); options.Commands["switch-to-nightly"] = typeof(SwitchToNightlyCommand);
options.Commands["translate"] = typeof(TranslateCommand); options.Commands["translate"] = typeof(TranslateCommand);
options.Commands["build"] = typeof(BuildCommand);
}); });
} }
} }

188
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DefaultChangedProjectFinder.cs

@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using LibGit2Sharp;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Build
{
public class DefaultChangedProjectFinder : IChangedProjectFinder, ITransientDependency
{
private readonly IRepositoryBuildStatusStore _repositoryBuildStatusStore;
public DefaultChangedProjectFinder(IRepositoryBuildStatusStore repositoryBuildStatusStore)
{
_repositoryBuildStatusStore = repositoryBuildStatusStore;
}
public List<DotNetProjectInfo> Find(DotNetProjectBuildConfig buildConfig)
{
if (buildConfig.SlFilePath.IsNullOrEmpty())
{
return FindByRepository(buildConfig.GitRepository);
}
return FindBySlnFile(buildConfig.GitRepository, buildConfig.SlFilePath);
}
private List<DotNetProjectInfo> FindByRepository(GitRepository gitRepository)
{
var changedProjectList = new List<DotNetProjectInfo>();
var gitRepositoryBuildStatus = _repositoryBuildStatusStore.Get(gitRepository);
FindChangedFiles(gitRepository, gitRepositoryBuildStatus, changedProjectList);
return changedProjectList;
}
private List<DotNetProjectInfo> FindBySlnFile(GitRepository gitRepository, string slnFilePath)
{
var slFine = new FileInfo(slnFilePath);
var changedProjectList = new List<DotNetProjectInfo>();
var csProjFiles = slFine.Directory.GetFiles(
"*.csproj",
SearchOption.AllDirectories
).Select(e => e.FullName)
.ToList();
foreach (var csProjFile in csProjFiles)
{
AddDependingProjectsToList(gitRepository, csProjFile, changedProjectList);
}
return changedProjectList;
}
private void AddDependingProjectsToList(
GitRepository gitRepository,
string csProjFilePath,
List<DotNetProjectInfo> changedProjectList)
{
var repositoryName = gitRepository.FindRepositoryOf(csProjFilePath);
var project = new DotNetProjectInfo(repositoryName, csProjFilePath);
if (changedProjectList.Any(e => e.CsProjPath == csProjFilePath))
{
return;
}
changedProjectList.Add(project);
AddProjectDependencies(gitRepository, project, changedProjectList);
}
private void AddProjectDependencies(GitRepository gitRepository, DotNetProjectInfo project, List<DotNetProjectInfo> changedProjectList)
{
var projectNode = XElement.Load(project.CsProjPath);
var referenceNodes = projectNode.Descendants("ItemGroup").Descendants("ProjectReference");
foreach (var referenceNode in referenceNodes)
{
if (referenceNode.Attribute("Include") == null)
{
continue;
}
var relativePath = referenceNode.Attribute("Include").Value;
var file = new FileInfo(project.CsProjPath);
var referenceProjectInfo = new FileInfo(Path.Combine(file.Directory.FullName, relativePath));
if (changedProjectList.Any(e => e.CsProjPath == referenceProjectInfo.FullName))
{
continue;
}
var repositoryName = gitRepository.FindRepositoryOf(referenceProjectInfo.FullName);
var referenceProject = new DotNetProjectInfo(repositoryName, referenceProjectInfo.FullName);
changedProjectList.Add(referenceProject);
AddProjectDependencies(gitRepository, referenceProject, changedProjectList);
}
}
private void FindChangedFiles(
GitRepository repository,
GitRepositoryBuildStatus repositoryBuildStatus,
List<DotNetProjectInfo> changedProjectList)
{
if (repositoryBuildStatus.CommitId.IsNullOrEmpty())
{
AddAllCsProjFiles(repository, changedProjectList);
}
else
{
AddChangedCsProjFiles(repository, changedProjectList, repositoryBuildStatus);
}
if (repository.DependingRepositories.Any())
{
foreach (var dependingRepository in repository.DependingRepositories)
{
var dependingRepositoryBuildStatus = repositoryBuildStatus.GetChild(dependingRepository.Name);
FindChangedFiles(dependingRepository, dependingRepositoryBuildStatus, changedProjectList);
}
}
}
private void AddAllCsProjFiles(GitRepository repository, List<DotNetProjectInfo> changedFiles)
{
var allCsProjFiles = Directory.GetFiles(
repository.RootPath,
"*.csproj",
SearchOption.AllDirectories
);
foreach (var file in allCsProjFiles)
{
changedFiles.Add(
new DotNetProjectInfo(repository.Name, Path.Combine(repository.RootPath, file))
);
}
}
private void AddChangedCsProjFiles(
GitRepository repository,
List<DotNetProjectInfo> changedFiles,
GitRepositoryBuildStatus status)
{
using (var repo = new Repository(string.Concat(repository.RootPath, @"\.git")))
{
var firstCommit = status.CommitId.IsNullOrEmpty()
? null
: repo.Lookup<Commit>(status.CommitId);
var repoDifferences = repo.Diff.Compare<Patch>(firstCommit?.Tree, repo.Head.Tip.Tree);
var files = repoDifferences
.Where(e => e.Path.EndsWith(".cs") || e.Path.EndsWith(".csproj"))
.Where(e => e.Status != ChangeKind.Deleted)
.Select(e => e)
.ToList();
foreach (var file in files)
{
var csProjPath = Path.Combine(repository.RootPath, file.Path);
if (status.SucceedProjects.Any(p => p.CsProjPath == csProjPath && p.CommitId == "1"))
{
continue;
}
changedFiles.Add(
new DotNetProjectInfo(repository.Name, csProjPath)
);
}
if (!repository.DependingRepositories.Any())
{
return;
}
foreach (var subRepository in repository.DependingRepositories)
{
var subRepositoryBuildStatus = status.GetChild(subRepository.Name);
FindChangedFiles(subRepository, subRepositoryBuildStatus, changedFiles);
}
}
}
}
}

72
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DefaultDotNetProjectBuilder.cs

@ -0,0 +1,72 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Build
{
public class DefaultDotNetProjectBuilder : IDotNetProjectBuilder, ITransientDependency
{
public List<string> Build(List<DotNetProjectInfo> projects, int maxParallelBuildCount, string arguments)
{
var builtProjects = new ConcurrentBag<string>();
try
{
foreach (var project in projects)
{
if (builtProjects.Contains(project.CsProjPath))
{
continue;
}
BuildInternal(project, arguments, builtProjects);
if (!project.Dependencies.Any())
{
continue;
}
// TODO: use parallel foreach here.
foreach (var projectDependency in project.Dependencies)
{
if (builtProjects.Contains(project.CsProjPath))
{
continue;
}
BuildInternal(projectDependency, arguments, builtProjects);
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
return builtProjects.ToList();
}
private void BuildInternal(DotNetProjectInfo project, string arguments, ConcurrentBag<string> builtProjects)
{
Console.WriteLine("Building...: dotnet build " + project.CsProjPath + " " + arguments);
CmdHelper.RunCmdAndGetOutput(
"dotnet build " + project.CsProjPath + " " + arguments,
out int buildStatus
);
if (buildStatus == 0)
{
builtProjects.Add(project.CsProjPath);
}
else
{
// TODO: throw exception and stop build process.
Console.WriteLine("Build failed for :" + project.CsProjPath);
}
}
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DotNetProjectBuildConfig.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.Cli.Build
{
public class DotNetProjectBuildConfig
{
public string SlFilePath { get; set; }
public GitRepository GitRepository { get; set; }
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DotNetProjectBuildStatus.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.Cli.Build
{
public class DotNetProjectBuildStatus
{
public string CsProjPath { get; set; }
public string CommitId { get; set; }
}
}

93
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DotNetProjectDependencyFiller.cs

@ -0,0 +1,93 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Build
{
public class DotNetProjectDependencyFiller : IDotNetProjectDependencyFiller, ITransientDependency
{
public ILogger<DotNetProjectDependencyFiller> Logger { get; set; }
public void Fill(List<DotNetProjectInfo> projects)
{
foreach (var project in projects)
{
FillProjectDependencies(project);
}
}
private void FillProjectDependencies(DotNetProjectInfo project)
{
var projectNode = XElement.Load(project.CsProjPath);
var referenceNodes = projectNode.Descendants("ItemGroup").Descendants("ProjectReference");
foreach (var referenceNode in referenceNodes)
{
if (referenceNode.Attribute("Include") == null)
{
continue;
}
var relativePath = referenceNode.Attribute("Include").Value;
var file = new FileInfo(project.CsProjPath);
var referenceProjectInfo = new FileInfo(Path.Combine(file.Directory.FullName, relativePath));
var referenceProject = new DotNetProjectInfo(project.RepositoryName, referenceProjectInfo.FullName);
project.Dependencies.Add(referenceProject);
}
}
private void GetProjectsOfRepository(GitRepository repository, List<string> projectPaths)
{
Logger.LogInformation("repo name:" + repository.Name);
Logger.LogInformation("directoryPath:" + repository.RootPath);
GetProjectsOfADirectory(repository.RootPath, projectPaths, new List<string>());
if (!repository.DependingRepositories.Any())
{
return;
}
foreach (var dependantRepository in repository.DependingRepositories)
{
GetProjectsOfRepository(dependantRepository, projectPaths);
}
}
private void GetProjectsOfADirectory(
string directoryPath,
List<string> projectPaths,
List<string> ignoredDirectories)
{
Logger.LogInformation("directoryPath:" + directoryPath);
var files = Directory.GetFiles(directoryPath, "*.csproj", SearchOption.AllDirectories)
.Select(f => f)
.ToList();
// foreach (var ignoredDirectory in ignoredDirectories)
// {
// files = files.Where(e => !e.StartsWith(Path.Combine(directoryPath, ignoredDirectory)))
// .ToList();
// }
projectPaths.AddRange(files);
// foreach (var projectFile in files)
// {
// var projectNode = XElement.Load(projectFile);
// if (projectNode.Attribute("Sdk") == null)
// {
// continue;
// }
//
// projectPaths.Add(projectFile);
// }
}
}
}

22
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/DotNetProjectInfo.cs

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Cli.Build
{
[Serializable]
public class DotNetProjectInfo
{
public string RepositoryName { get; set; }
public string CsProjPath { get; set; }
public List<DotNetProjectInfo> Dependencies { get; set; }
public DotNetProjectInfo(string repositoryName, string csProjPath)
{
RepositoryName = repositoryName;
CsProjPath = csProjPath;
Dependencies = new List<DotNetProjectInfo>();
}
}
}

91
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/GitRepository.cs

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Cli.Build
{
/// <summary>
/// Represents a source code repository
/// </summary>
public class GitRepository
{
/// <summary>
/// Name of the repository
/// </summary>
public string Name { get; set; }
/// <summary>
/// Branch of the repository
/// </summary>
public string BranchName { get; set; }
/// <summary>
/// Root path of the repository which contains .git folder
/// </summary>
public string RootPath { get; set; }
public List<GitRepository> DependingRepositories { get; set; }
public GitRepository(string name, string branchName, string rootPath)
{
Name = name;
BranchName = branchName;
RootPath = rootPath;
DependingRepositories = new List<GitRepository>();
}
public string GetUniqueName()
{
var name = Name + "_" + BranchName;
foreach (var dependingRepository in DependingRepositories)
{
AddToUniqueName(dependingRepository, name);
}
return name.ToMd5();
}
private void AddToUniqueName(GitRepository gitRepository, string name)
{
name += "_" + gitRepository.Name + "_" + gitRepository.BranchName;
foreach (var dependingRepository in gitRepository.DependingRepositories)
{
AddToUniqueName(dependingRepository, name);
}
}
public string FindRepositoryOf(string csProjFilePath)
{
if (csProjFilePath.StartsWith(RootPath))
{
return Name;
}
foreach (var dependingRepository in DependingRepositories)
{
var name = FindRepositoryOfInternal(dependingRepository, csProjFilePath);
if (!string.IsNullOrEmpty(name))
{
return name;
}
}
return null;
}
private string FindRepositoryOfInternal(GitRepository repository, string csProjFilePath)
{
if (csProjFilePath.StartsWith(repository.RootPath))
{
return repository.Name;
}
foreach (var dependingRepository in repository.DependingRepositories)
{
return FindRepositoryOfInternal(dependingRepository, csProjFilePath);
}
return null;
}
}
}

88
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/GitRepositoryBuildStatus.cs

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Cli.Build
{
public class GitRepositoryBuildStatus
{
/// <summary>
/// Name of the repository
/// </summary>
public string Name { get; set; }
/// <summary>
/// Branch of the repository
/// </summary>
public string BranchName { get; set; }
/// <summary>
/// Last succeeded commitId of the repository
/// </summary>
public string CommitId { get; set; }
/// <summary>
/// Build succeeded projects of this repository
/// </summary>
public List<DotNetProjectBuildStatus> SucceedProjects { get; set; }
/// <summary>
/// Build status of depending repositories
/// </summary>
public List<GitRepositoryBuildStatus> DependingRepositories { get; set; }
public GitRepositoryBuildStatus(string name, string branchName)
{
Name = name;
BranchName = branchName;
SucceedProjects = new List<DotNetProjectBuildStatus>();
DependingRepositories = new List<GitRepositoryBuildStatus>();
}
public GitRepositoryBuildStatus GetChild(string repositoryName)
{
foreach (var dependingRepository in DependingRepositories)
{
return GetChildInternal(dependingRepository, repositoryName);
}
return null;
}
private GitRepositoryBuildStatus GetChildInternal(GitRepositoryBuildStatus repositoryBuildStatus,
string repositoryName)
{
if (repositoryBuildStatus.Name == repositoryName)
{
return repositoryBuildStatus;
}
foreach (var dependingRepository in repositoryBuildStatus.DependingRepositories)
{
return GetChildInternal(dependingRepository, repositoryName);
}
return null;
}
public string GetUniqueName()
{
var name = Name + "_" + BranchName;
foreach (var dependingRepository in DependingRepositories)
{
AddToUniqueName(dependingRepository, name);
}
return name.ToMd5();
}
private void AddToUniqueName(GitRepositoryBuildStatus gitRepository, string name)
{
name += "_" + gitRepository.Name + "_" + gitRepository.BranchName;
foreach (var dependingRepository in gitRepository.DependingRepositories)
{
AddToUniqueName(dependingRepository, name);
}
}
}
}

69
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IBuildArgsReader.cs

@ -0,0 +1,69 @@
using System;
using System.IO;
using System.Linq;
using LibGit2Sharp;
using Volo.Abp.Json;
namespace Volo.Abp.Cli.Build
{
public interface IDotNetProjectBuildConfigReader
{
DotNetProjectBuildConfig Read(string directoryPath);
}
public class FileSystemDotNetProjectBuildConfigReader : IDotNetProjectBuildConfigReader
{
private IJsonSerializer _jsonSerializer;
public FileSystemDotNetProjectBuildConfigReader(IJsonSerializer jsonSerializer)
{
_jsonSerializer = jsonSerializer;
}
public DotNetProjectBuildConfig Read(string directoryPath)
{
var buildArgs = new DotNetProjectBuildConfig();
var solutionFiles = Directory.GetFiles(directoryPath, "*.sln", SearchOption.TopDirectoryOnly);
if (solutionFiles.Length == 1)
{
buildArgs.SlFilePath = solutionFiles.First();
}
else
{
Console.WriteLine(
"There are more than 1 solution (*.sln) file in the directory. Searching for build-config.json file."
);
}
var configFiles = Directory.GetFiles(directoryPath, "abp-build-config.json", SearchOption.TopDirectoryOnly);
if (configFiles.Length == 1)
{
var configFile = configFiles.First();
buildArgs.GitRepository = _jsonSerializer.Deserialize<GitRepository>(configFile);
}
else
{
Console.WriteLine(
"There are more than 1 config (abp-build-config.json) file in the directory!"
);
}
SetBranchNames(buildArgs.GitRepository);
return buildArgs;
}
private void SetBranchNames(GitRepository gitRepository)
{
using (var repo = new Repository(string.Concat(gitRepository.RootPath, @"\.git")))
{
gitRepository.BranchName = repo.Head.FriendlyName;
}
foreach (var dependingRepository in gitRepository.DependingRepositories)
{
SetBranchNames(dependingRepository);
}
}
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IChangedProjectFinder.cs

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Volo.Abp.Cli.Build
{
public interface IChangedProjectFinder
{
List<DotNetProjectInfo> Find(DotNetProjectBuildConfig buildConfig);
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IDotNetProjectBuilder.cs

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Volo.Abp.Cli.Build
{
public interface IDotNetProjectBuilder
{
List<string> Build(List<DotNetProjectInfo> projects, int maxParallelBuildCount, string arguments);
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IDotNetProjectDependencyFiller.cs

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Volo.Abp.Cli.Build
{
public interface IDotNetProjectDependencyFiller
{
void Fill(List<DotNetProjectInfo> projects);
}
}

58
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Build/IRepositoryBuildStatusStore.cs

@ -0,0 +1,58 @@
using System.IO;
using Newtonsoft.Json;
using Volo.Abp.DependencyInjection;
using Volo.Abp.IO;
namespace Volo.Abp.Cli.Build
{
public interface IRepositoryBuildStatusStore
{
GitRepositoryBuildStatus Get(GitRepository repository);
void Set(GitRepositoryBuildStatus status);
}
public class FileSystemRepositoryBuildStatusStore : IRepositoryBuildStatusStore, ITransientDependency
{
// TODO: change this ?
private string BaseBuildStatusStorePath = @"C:\Users\ismai\.abp\build";
public GitRepositoryBuildStatus Get(GitRepository repository)
{
if (!Directory.Exists(BaseBuildStatusStorePath))
{
Directory.CreateDirectory(BaseBuildStatusStorePath);
}
var buildStatusFile = Path.Combine(BaseBuildStatusStorePath, repository.GetUniqueName()) + ".json";
if (!File.Exists(buildStatusFile))
{
// TODO: this is wrong
return new GitRepositoryBuildStatus(repository.Name, repository.BranchName);
}
var buildStatusText = File.ReadAllText(buildStatusFile);
return JsonConvert.DeserializeObject<GitRepositoryBuildStatus>(buildStatusText);
}
public void Set(GitRepositoryBuildStatus status)
{
if (!Directory.Exists(BaseBuildStatusStorePath))
{
Directory.CreateDirectory(BaseBuildStatusStorePath);
}
var buildStatusFile = Path.Combine(BaseBuildStatusStorePath, status.GetUniqueName()) + ".json";
if (File.Exists(buildStatusFile))
{
FileHelper.DeleteIfExists(buildStatusFile);
}
using (var file = File.CreateText(buildStatusFile))
{
new JsonSerializer {Formatting = Formatting.Indented}.Serialize(file, status);
}
}
}
}

180
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/BuildCommand.cs

@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LibGit2Sharp;
using Microsoft.Extensions.Logging;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Build;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public class BuildCommand : IConsoleCommand, ITransientDependency
{
public ILogger<BuildCommand> Logger { get; set; }
public IDotNetProjectDependencyFiller DotNetProjectDependencyFiller { get; set; }
public IChangedProjectFinder ChangedProjectFinder { get; set; }
public IDotNetProjectBuilder DotNetProjectBuilder { get; set; }
public IRepositoryBuildStatusStore RepositoryBuildStatusStore { get; set; }
public IDotNetProjectBuildConfigReader DotNetProjectBuildConfigReader { get; set; }
public Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
var sw = new Stopwatch();
sw.Start();
var buildConfig = DotNetProjectBuildConfigReader.Read(Directory.GetCurrentDirectory());
var maxParallelBuild = commandLineArgs.Options.GetOrNull(
Options.MaxParallelBuild.Short,
Options.MaxParallelBuild.Long
);
var dotnetBuildArguments = commandLineArgs.Options.GetOrNull(Options.DotnetBuildArguments.Short,
Options.DotnetBuildArguments.Long);
var changedProjectFiles = ChangedProjectFinder.Find(buildConfig);
DotNetProjectDependencyFiller.Fill(changedProjectFiles);
var sortedProjects = changedProjectFiles.SortByDependencies(p => p.Dependencies);
var buildSucceededProjects = DotNetProjectBuilder.Build(
sortedProjects,
string.IsNullOrEmpty(maxParallelBuild) ? 1 : Convert.ToInt32(maxParallelBuild),
dotnetBuildArguments ?? ""
);
var buildStatus = GenerateBuildStatus(buildConfig.GitRepository, changedProjectFiles, buildSucceededProjects);
RepositoryBuildStatusStore.Set(buildStatus);
sw.Stop();
Console.WriteLine("Build operation is completed in " + sw.ElapsedMilliseconds + " (ms)");
return Task.CompletedTask;
}
private GitRepositoryBuildStatus GenerateBuildStatus(
GitRepository gitRepository,
List<DotNetProjectInfo> changedProjects,
List<string> buildSucceededProjects)
{
using (var repo = new Repository(string.Concat(gitRepository.RootPath, @"\.git")))
{
var lastCommitId = repo.Head.Tip.Id.ToString();
var status = new GitRepositoryBuildStatus(
gitRepository.Name,
repo.Head.FriendlyName
)
{
CommitId = lastCommitId
};
status.SucceedProjects = changedProjects.Where(p =>
p.RepositoryName == gitRepository.Name &&
buildSucceededProjects.Contains(p.CsProjPath)
)
.Select(e => new DotNetProjectBuildStatus()
{
CsProjPath = e.CsProjPath,
CommitId = lastCommitId
}).ToList();
foreach (var dependingRepository in gitRepository.DependingRepositories)
{
GenerateBuildStatusInternal(dependingRepository, changedProjects, buildSucceededProjects, status);
}
return status;
}
}
private void GenerateBuildStatusInternal(
GitRepository gitRepository,
List<DotNetProjectInfo> changedProjects,
List<string> buildSucceededProjects,
GitRepositoryBuildStatus status)
{
using (var repo = new Repository(string.Concat(gitRepository.RootPath, @"\.git")))
{
var lastCommitId = repo.Head.Tip.Id.ToString();
var dependingRepositoryStatus = new GitRepositoryBuildStatus(
gitRepository.Name,
repo.Head.FriendlyName
)
{
CommitId = lastCommitId
};
dependingRepositoryStatus.SucceedProjects = changedProjects.Where(p =>
p.RepositoryName == gitRepository.Name &&
buildSucceededProjects.Contains(p.CsProjPath)
)
.Select(e => new DotNetProjectBuildStatus()
{
CsProjPath = e.CsProjPath,
CommitId = lastCommitId
}).ToList();
foreach (var dependingRepository in gitRepository.DependingRepositories)
{
GenerateBuildStatusInternal(
dependingRepository,
changedProjects,
buildSucceededProjects,
dependingRepositoryStatus
);
}
status.DependingRepositories.Add(dependingRepositoryStatus);
}
}
public string GetUsageInfo()
{
var sb = new StringBuilder();
sb.AppendLine("");
sb.AppendLine("Usage:");
sb.AppendLine("");
sb.AppendLine(" abp build [options]");
sb.AppendLine("");
sb.AppendLine("Options:");
sb.AppendLine("");
// TODO: Explain extra parameters
sb.AppendLine("");
sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI");
return sb.ToString();
}
public string GetShortDescription()
{
return "Builds a dotnet repository and dependent repositories or a solution.";
}
public static class Options
{
public static class MaxParallelBuild
{
public const string Short = "m";
public const string Long = "max-paralel-builds";
}
public static class DotnetBuildArguments
{
public const string Short = "d";
public const string Long = "dotnet-build-arguments";
}
}
}
}
Loading…
Cancel
Save