Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for overriding repository url, version and uploading multiple packages simultaneously using a glob pattern (wildcards) #53

Merged
merged 43 commits into from
Jun 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
f30e12d
Add support for overriding nuspec repository url and version before p…
peters Jun 12, 2020
3d5de9a
Add support for wildcards when pushing. Fixes #30
peters Jun 13, 2020
1f7699f
Add additional test cases. Ref. https://github.com/jcansdale/gpr/pull…
peters Jun 15, 2020
78258d6
Add support for *.snupkg (symbol packages) and parallelization allowi…
peters Jun 15, 2020
5874ae5
Add additional test cases.
peters Jun 15, 2020
8810332
Ignore repository type when determining if we should rewrite nupkg as…
peters Jun 15, 2020
30e1dd8
If --repository option is not supplied then read <RepositoryUrl /> fr…
peters Jun 15, 2020
dfa4ec4
Add support for wildcards (glob patterns), symbol packages (.snupkg) …
peters Jun 15, 2020
554e459
Remove all whitespace tokens after reading access token.
peters Jun 15, 2020
a114198
Add test case that proves whitespace is removed from repository url.
peters Jun 15, 2020
7677bb7
Add shorthand syntax for new push command options.
peters Jun 15, 2020
c3cb47a
Fix bad formatting.
peters Jun 15, 2020
1f417fd
Merge branch 'master' into issue-48
peters Jun 15, 2020
328a018
Add additional test cases.
peters Jun 15, 2020
a47485d
Add retry policy in order to deal with intermittent connection issue.
peters Jun 15, 2020
f870f07
Bugfix: Support relative urls. E.g owner/repositoryname. Also always …
peters Jun 15, 2020
50878c5
Add support for expanding a relative path combined with a base direct…
peters Jun 15, 2020
fe86d60
Cancel push if "CTRL - C" is pressed.
peters Jun 16, 2020
e3cb47a
Address latest feedback.
peters Jun 16, 2020
6daa0cd
Add support for cancellation of all commands and return non-zero exit…
peters Jun 16, 2020
7125edb
Update src/GprTool/Program.cs
peters Jun 16, 2020
236e99b
Add environment variable for debugging. The process will wait until d…
peters Jun 16, 2020
6b0c324
Optimize package search by moving check if nupkg should be written in…
peters Jun 16, 2020
8949086
Remove unused variable.
peters Jun 16, 2020
063f22f
R#
peters Jun 16, 2020
daf0551
If PackageFilename is a directory then we should by default upload al…
peters Jun 16, 2020
4a8df4c
Implicitly cast workingdirectory to string.
peters Jun 16, 2020
623bfce
Use full path in glob
jcansdale Jun 16, 2020
04fd2b4
Refactor: Expand path before parsing glob pattern. Added test cases f…
peters Jun 16, 2020
8fd11e6
Add additional test cases.
peters Jun 16, 2020
be0e251
Update nuget packages. Maybe consider enabling depandabot? /cc @jcans…
peters Jun 16, 2020
b94c540
Enable running tests via commandline: dotnet test . --logger:nunit /p…
peters Jun 16, 2020
4092898
Change package output path root solution directory.
peters Jun 16, 2020
9b823ad
Add global json.
peters Jun 16, 2020
38b72ee
Fix failing test cases on Unix.
peters Jun 17, 2020
9523c16
PackageOutputPath is already defined in Directory.Build.Props.
peters Jun 17, 2020
8fac910
Update src/GprTool/NuGetUtilities.cs
peters Jun 17, 2020
ec536b0
Ignore nupkgs directory.
peters Jun 17, 2020
d253600
Merge branch 'issue-48' of https://github.com/peters/gpr into issue-48
peters Jun 17, 2020
47f0409
Remove FilenameWithoutGprPrefix and use ".zip" extension when rewriti…
peters Jun 17, 2020
8af6bda
Add support for accepting multiple filenames (relative or absolute) a…
peters Jun 17, 2020
237eef7
Enable OSX support.
peters Jun 17, 2020
0294e2c
Update test syntax because packages list may be sorted differently ba…
peters Jun 17, 2020
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
**/.vs/
**/.vs/
**/bin/
**/obj/
*.user
*.nupkg
_NCrunch_*/
*.ncrunchsolution
publish/
nupkgs/
src/GprTool/nupkg/
**/TestResults/TestResults.xml
31 changes: 25 additions & 6 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning">
<Version>3.0.50</Version>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<IsRunningTests Condition="'$(IsRunningTests)' == ''">false</IsRunningTests>
<PackageOutputPath>$(MSBuildThisFileDirectory)nupkgs</PackageOutputPath>
<OsPlatform Condition="$(OsPlatform) == '' AND '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">Windows</OsPlatform>
<OsPlatform Condition="$(OsPlatform) == '' AND '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">Unix</OsPlatform>
<OsPlatform Condition="$(OsPlatform) == '' AND '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">MACOS</OsPlatform>
<OsPlatform Condition="$(OsPlatform) == ''">Unknown</OsPlatform>
</PropertyGroup>

<PropertyGroup Condition="$(IsRunningTests)">
<DefineConstants>$(DefineConstants);IS_RUNNING_TESTS</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(OsPlatform) == 'Windows'">
<DefineConstants>$(DefineConstants);PLATFORM_WINDOWS</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(OsPlatform) == 'Unix'">
<DefineConstants>$(DefineConstants);PLATFORM_UNIX</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(OsPlatform) == 'MACOS'">
<DefineConstants>$(DefineConstants);PLATFORM_MACOS</DefineConstants>
</PropertyGroup>

</Project>
5 changes: 5 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sdk": {
"version": "3.1.301"
}
}
46 changes: 46 additions & 0 deletions src/GprTool/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace GprTool
{
internal static class EnumerableExtensions
{
public static Task ForEachAsync<T>([NotNull] this IEnumerable<T> source,
[NotNull] Func<T, CancellationToken, Task> onExecuteFunc, Action<T, Exception> onExceptionAction = null,
CancellationToken cancellationToken = default, int concurrency = 1)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (onExecuteFunc == null) throw new ArgumentNullException(nameof(onExecuteFunc));
if (concurrency <= 0) throw new ArgumentOutOfRangeException(nameof(concurrency));

// https://devblogs.microsoft.com/pfxteam/implementing-a-simple-foreachasync-part-2/
return Task.WhenAll(
Partitioner
.Create(source)
.GetPartitions(concurrency)
.Select(partition => Task.Run(async delegate
{
using (partition)
{
while (partition.MoveNext())
{
try
{
await onExecuteFunc(partition.Current, cancellationToken);
}
catch (Exception e)
{
onExceptionAction?.Invoke(partition.Current, e);
throw;
}
}
}
}, default)));
}
}
}
86 changes: 86 additions & 0 deletions src/GprTool/GlobExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using DotNet.Globbing;
using DotNet.Globbing.Token;

namespace GprTool
{
public static class GlobExtensions
{
public static bool IsGlobPattern(this Glob glob)
{
return glob.Tokens.Any(x => !(x is PathSeparatorToken || x is LiteralToken));
}

public static string BuildBasePathFromGlob(this Glob glob, string baseDirectory)
{
if (glob == null) throw new ArgumentNullException(nameof(glob));
if (baseDirectory == null) throw new ArgumentNullException(nameof(baseDirectory));

var globTokens = glob.Tokens.ToList();
var pathTokens = new List<IGlobToken>();

for (var index = 0; index < globTokens.Count; index++)
{
var token = glob.Tokens[index];
var tokenNext = index + 1 < globTokens.Count ? glob.Tokens[index + 1] : null;

switch (token)
{
case LiteralToken _:
pathTokens.Add(token);
if (tokenNext is AnyCharacterToken
|| tokenNext is INegatableToken
&& pathTokens.Any())
{
pathTokens.RemoveAt(pathTokens.Count - 1);
goto done;
}
continue;
case PathSeparatorToken _ when (tokenNext is LiteralToken):
pathTokens.Add(token);
continue;
}

goto done;
}

done:

var pathStringBuilder = new StringBuilder();

foreach (var token in pathTokens)
{
switch (token)
{
case LiteralToken literalToken:
pathStringBuilder.Append(literalToken.Value);
break;
case PathSeparatorToken _: // xplat
pathStringBuilder.Append("/");
break;
default:
throw new NotSupportedException(token.GetType().FullName);
}
}

var pathStr = pathStringBuilder.ToString();

// Remove trailing backward/forward slash
var lastAppendedGlobToken = pathTokens.LastOrDefault();
if (lastAppendedGlobToken is PathSeparatorToken
&& pathStr.Sum(x => x == '/' ? 1 : 0) > 1)
{
pathStr = pathStr.Substring(0, pathStr.Length - 1);
} else if (lastAppendedGlobToken is LiteralToken literalToken && literalToken.Value == ".")
{
return Path.GetFullPath(baseDirectory);
}

return !Path.IsPathRooted(pathStr) ? Path.GetFullPath(pathStr, baseDirectory) : Path.GetFullPath(pathStr);
}
}
}
12 changes: 9 additions & 3 deletions src/GprTool/GprTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@
<PackageProjectUrl>https://github.com/jcansdale/gpr</PackageProjectUrl>
<Title>GPR Tool</Title>
<PackageDescription>A .NET Core tool for working the GitHub Package Registry.</PackageDescription>
<PackageOutputPath>./nupkg</PackageOutputPath>
<AssemblyName>gpr</AssemblyName>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<Copyright>Mutant Design Limited</Copyright>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.4.1" />
<PackageReference Include="DotNet.Glob" Version="3.0.9" />
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="3.0.0" />
<PackageReference Include="Octokit.GraphQL" Version="0.1.4-packages-preview2" />
<PackageReference Include="RestSharp" Version="106.10.1" />
<PackageReference Include="Polly" Version="7.2.1" />
<PackageReference Include="RestSharp" Version="106.11.4" />
<PackageReference Include="NuGet.Packaging" Version="5.6.0" />
<PackageReference Include="Nerdbank.GitVersioning" Condition="!$(IsRunningTests)">
<Version>3.1.91</Version>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

</Project>
69 changes: 69 additions & 0 deletions src/GprTool/IoExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DotNet.Globbing;

namespace GprTool
{
public static class IoExtensions
{
public static IEnumerable<string> GetFilesByGlobPattern(this string baseDirectory, string globPattern, out Glob outGlob)
{
var baseDirectoryGlobPattern = Path.GetFullPath(Path.Combine(baseDirectory, globPattern));
var fileNames = new List<string>();

if (string.Equals(".", globPattern))
{
globPattern = Path.GetFullPath(Path.Combine(baseDirectory, "*.*"));
} else if (Directory.Exists(baseDirectoryGlobPattern))
{
globPattern = Path.GetFullPath(Path.Combine(baseDirectoryGlobPattern, "*.*"));
} else if (File.Exists(baseDirectoryGlobPattern))
{
globPattern = Path.GetFullPath(baseDirectoryGlobPattern);
} else if (globPattern.Contains(" "))
{
baseDirectoryGlobPattern = baseDirectory;

fileNames.AddRange(globPattern
.Split(" ", StringSplitOptions.RemoveEmptyEntries)
.Select(x => Path.IsPathRooted(x)
? Path.GetFullPath(x)
: Path.GetFullPath(Path.Combine(baseDirectoryGlobPattern, x)))
.Where(x => !Directory.Exists(x)));

globPattern = string.Empty;
}

var glob = Path.IsPathRooted(globPattern)
? Glob.Parse(globPattern)
: Glob.Parse(baseDirectoryGlobPattern);

var basePathFromGlob = Path.GetDirectoryName(glob.BuildBasePathFromGlob(baseDirectory));

outGlob = glob;

return Directory
.GetFiles(basePathFromGlob, "*.*", SearchOption.AllDirectories)
.Where(filename =>
filename.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase)
|| filename.EndsWith(".snupkg", StringComparison.OrdinalIgnoreCase))
.Where(filename => fileNames.Contains(filename, StringComparer.Ordinal) || glob.IsMatch(filename));
}

public static FileStream OpenReadShared(this string filename)
{
return File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
}

public static MemoryStream ReadSharedToStream(this string filename)
{
using var fileStream = filename.OpenReadShared();
var outputStream = new MemoryStream();
fileStream.CopyTo(outputStream);
outputStream.Seek(0, SeekOrigin.Begin);
return outputStream;
}
}
}
Loading