diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index df72e7f..5851c9c 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,12 +15,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: - dotnet-version: '7.x.x' + dotnet-version: '9.x.x' - name: Restore dependencies run: dotnet restore @@ -46,7 +46,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set version from branch name id: set_version @@ -63,9 +63,9 @@ jobs: echo "image_name=$lowercase" >> $GITHUB_OUTPUT - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: - dotnet-version: '7.x.x' + dotnet-version: '9.x.x' - name: Restore dependencies run: dotnet restore @@ -79,7 +79,7 @@ jobs: mv bin/Release/publish/VRLabs.VRCTools.Packaging.Console bin/Release/publish/VRCPackagingTool${1##*.} - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: VRCPackagingTool-${{ matrix.RUNTIME }} path: bin/Release/publish/ @@ -89,7 +89,7 @@ jobs: needs: build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set version from branch name id: set_version @@ -110,7 +110,7 @@ jobs: sed -i "s/.*<\/Version>/${{ steps.set_version.outputs.version }}<\/Version>/" VRLabs.VRCTools.Packaging.Console/VRLabs.VRCTools.Packaging.Console.csproj - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -119,7 +119,7 @@ jobs: # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - name: Build and push Docker image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: context: . file: ./VRLabs.VRCTools.Packaging.Console/Dockerfile @@ -135,7 +135,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set version from branch name id: set_version @@ -151,9 +151,10 @@ jobs: echo "image_name=$lowercase" >> $GITHUB_OUTPUT - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: bin/Release/publish + pattern: VRCPackagingTool-* - name: Zip each artifact run: | @@ -174,4 +175,4 @@ jobs: files: | bin/Release/publish/VRCPackagingTool-linux-x64.zip bin/Release/publish/VRCPackagingTool-win-x64.zip - bin/Release/publish/VRCPackagingTool-osx-x64.zip \ No newline at end of file + bin/Release/publish/VRCPackagingTool-osx-x64.zip diff --git a/README.md b/README.md index 9c04058..0f407e1 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,12 @@ Only generating the `vcc` package: VRCPackagingTool.exe "packageAssetsPath" "outputDirectorypath" --releaseUrl "vccReleaseUrl" --nounity ``` +With custom json fields in the `package.json`,useful for custom vcc clients that may use additional fields (for example [ALCOM's](https://vrc-get.anatawa12.com/alcom/) custom changelog url field): + +``` +VRCPackagingTool.exe "packageAssetsPath" "outputDirectorypath" --releaseUrl "vccReleaseUrl" --unityReleaseUrl "unityReleaseUrl" --customJsonFields "changelogUrl=https://link.to.changelog" "anotherField=anotherValue" +``` + You can use the `--help` or `-h` flag to get a list of all the available options. ``` @@ -49,16 +55,15 @@ Arguments: Output directory path Options: - --releaseUrl Url of the release [] - --unityReleaseUrl Url of the release of the unitypackage [] - --releaseVersion Version to use for the release, if not specified it will be taken from the package.json [] - --novcc don't build the vcc zip file [default: False] - --nounity don't build the unitypackage [default: False] - --action is it running on github actions? [default: False] - --version Show version information - -?, -h, --help Show help and usage information - - + --releaseUrl Url of the release [] + --unityReleaseUrl Url of the release of the unitypackage [] + --releaseVersion Version to use for the release, if not specified it will be taken from the package.json [] + --novcc don't build the vcc zip file [default: False] + --nounity don't build the unitypackage [default: False] + --action is it running on github actions? [default: False] + --customJsonFields custom json fields to add to the package.json [] + --version Show version information + -?, -h, --help Show help and usage information ``` @@ -75,7 +80,7 @@ The tool can use some additional fields in the `package.json` for the packaging (Fields marked with * are required for the UnityPackage generation) -And it adds some additional fields to the `package.json`: +And it adds some additional fields to the `package.json` (on top of the one passed via the `--customJsonFields` option): | Field | Description | |-------------------|--------------------------------------------------------------------| diff --git a/VRLabs.VRCTools.Packaging.Console/Dockerfile b/VRLabs.VRCTools.Packaging.Console/Dockerfile index 6f191e7..98283b6 100644 --- a/VRLabs.VRCTools.Packaging.Console/Dockerfile +++ b/VRLabs.VRCTools.Packaging.Console/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build WORKDIR /src COPY ["VRLabs.VRCTools.Packaging.Console/VRLabs.VRCTools.Packaging.Console.csproj", "VRLabs.VRCTools.Packaging.Console/"] RUN dotnet restore "VRLabs.VRCTools.Packaging.Console/VRLabs.VRCTools.Packaging.Console.csproj" @@ -9,6 +9,6 @@ RUN dotnet build "VRLabs.VRCTools.Packaging.Console.csproj" -c Release -o /app/b FROM build AS publish RUN dotnet publish "VRLabs.VRCTools.Packaging.Console.csproj" -c Release -o /app/publish /p:UseAppHost=false -FROM mcr.microsoft.com/dotnet/runtime:7.0 AS final +FROM mcr.microsoft.com/dotnet/runtime:9.0-alpine AS final COPY --from=publish /app/publish /app ENTRYPOINT ["dotnet", "/app/VRLabs.VRCTools.Packaging.Console.dll"] diff --git a/VRLabs.VRCTools.Packaging.Console/PackagingOptionsBinder.cs b/VRLabs.VRCTools.Packaging.Console/PackagingOptionsBinder.cs new file mode 100644 index 0000000..f6dc6da --- /dev/null +++ b/VRLabs.VRCTools.Packaging.Console/PackagingOptionsBinder.cs @@ -0,0 +1,62 @@ +using System.CommandLine; +using System.CommandLine.Binding; + +namespace VRLabs.VRCTools.Packaging.Console; + +public class PackagingOptionsBinder : BinderBase +{ + private readonly Argument _workingDirectoryArg; + private readonly Argument _outputDirectoryArg; + private readonly Option _releaseUrlOpt; + private readonly Option _unityReleaseUrlOpt; + private readonly Option _versionOpt; + private readonly Option _noVccOpt; + private readonly Option _noUnityOpt; + private readonly Option _actionOpt; + private readonly Option _customFieldsOpt; + + public PackagingOptionsBinder(Argument workingDirectoryArg, Argument outputDirectoryArg, Option releaseUrlOpt, + Option unityReleaseUrlOpt, Option versionOpt, Option noVccOpt, Option noUnityOpt, Option actionOpt, + Option customFieldsOpt) + { + _workingDirectoryArg = workingDirectoryArg; + _outputDirectoryArg = outputDirectoryArg; + _releaseUrlOpt = releaseUrlOpt; + _unityReleaseUrlOpt = unityReleaseUrlOpt; + _versionOpt = versionOpt; + _noVccOpt = noVccOpt; + _noUnityOpt = noUnityOpt; + _actionOpt = actionOpt; + _customFieldsOpt = customFieldsOpt; + } + + protected override PackagingOptions GetBoundValue(BindingContext bindingContext) => + new() + { + WorkingDirectory = bindingContext.ParseResult.GetValueForArgument(_workingDirectoryArg), + OutputDirectory = bindingContext.ParseResult.GetValueForArgument(_outputDirectoryArg), + ReleaseUrl = bindingContext.ParseResult.GetValueForOption(_releaseUrlOpt), + UnityPackageUrl = bindingContext.ParseResult.GetValueForOption(_unityReleaseUrlOpt), + Version = bindingContext.ParseResult.GetValueForOption(_versionOpt), + SkipVcc = bindingContext.ParseResult.GetValueForOption(_noVccOpt), + SkipUnityPackage = bindingContext.ParseResult.GetValueForOption(_noUnityOpt), + IsRunningOnGithubActions = bindingContext.ParseResult.GetValueForOption(_actionOpt), + CustomFields = GetDictionaryField(bindingContext.ParseResult.GetValueForOption(_customFieldsOpt)) + }; + + private Dictionary GetDictionaryField(string[]? values) + { + var dictionary = new Dictionary(); + + foreach (var kvp in values ?? []) + { + var split = kvp.Split('='); + if (split.Length >= 2) + { + dictionary.Add(split[0], string.Join("=", split[1..])); + } + } + + return dictionary; + } +} \ No newline at end of file diff --git a/VRLabs.VRCTools.Packaging.Console/Program.cs b/VRLabs.VRCTools.Packaging.Console/Program.cs index 1c711f9..d5cf30c 100644 --- a/VRLabs.VRCTools.Packaging.Console/Program.cs +++ b/VRLabs.VRCTools.Packaging.Console/Program.cs @@ -1,6 +1,7 @@ using System.CommandLine; using Serilog; using VRLabs.VRCTools.Packaging; +using VRLabs.VRCTools.Packaging.Console; Log.Logger = new LoggerConfiguration() .WriteTo.Console() @@ -14,6 +15,7 @@ var noVccOpt = new Option(name: "--novcc", getDefaultValue: () => false, description: "don't build the vcc zip file"); var noUnityOpt = new Option(name: "--nounity", getDefaultValue: () => false, description: "don't build the unitypackage"); var actionOpt = new Option(name: "--action", getDefaultValue: () => false, description: "is it running on github actions?"); +var customFieldsOpt = new Option(name: "--customJsonFields", getDefaultValue: () => [], description: "custom json fields to add to the package.json"){AllowMultipleArgumentsPerToken = true}; var command = new RootCommand("Packs the assets inside a folder in a Unity Project based on an info file") { @@ -24,15 +26,15 @@ versionOpt, noVccOpt, noUnityOpt, - actionOpt + actionOpt, + customFieldsOpt }; -command.SetHandler(async (source, output, releaseUrl, unityReleaseUrl, version, noVcc, noUnity, action) => +command.SetHandler(async (packagingOptions) => { try { - Environment.SetEnvironmentVariable("RUNNING_ON_GITHUB_ACTIONS", action ? "true" : "false"); - var result = await Packager.CreatePackage(source, output, releaseUrl, unityReleaseUrl, version, noVcc, noUnity); + var result = await Packager.CreatePackage(packagingOptions); if (!result) { Log.Error("Failed to create package"); @@ -45,6 +47,6 @@ Environment.Exit(1); } -}, pathArg, outputArg, releaseUrlOpt, unityReleaseUrlOpt, versionOpt, noVccOpt, noUnityOpt, actionOpt); +}, new PackagingOptionsBinder(pathArg, outputArg, releaseUrlOpt, unityReleaseUrlOpt, versionOpt, noVccOpt, noUnityOpt, actionOpt, customFieldsOpt)); command.Invoke(args); \ No newline at end of file diff --git a/VRLabs.VRCTools.Packaging.Console/VRLabs.VRCTools.Packaging.Console.csproj b/VRLabs.VRCTools.Packaging.Console/VRLabs.VRCTools.Packaging.Console.csproj index 43eaed2..469c917 100644 --- a/VRLabs.VRCTools.Packaging.Console/VRLabs.VRCTools.Packaging.Console.csproj +++ b/VRLabs.VRCTools.Packaging.Console/VRLabs.VRCTools.Packaging.Console.csproj @@ -2,17 +2,18 @@ Exe - net7.0 + net9.0 enable enable Linux - 1.1.999 + 1.2.999 false VRC Packaging Tool MIT VRLabs VRLabs Tool to package assets both in UnityPackage and VRChat's vcc format + 13 @@ -22,8 +23,8 @@ - - + + diff --git a/VRLabs.VRCTools.Packaging/Packager.cs b/VRLabs.VRCTools.Packaging/Packager.cs index e4581e5..e8a4c05 100644 --- a/VRLabs.VRCTools.Packaging/Packager.cs +++ b/VRLabs.VRCTools.Packaging/Packager.cs @@ -11,48 +11,53 @@ namespace VRLabs.VRCTools.Packaging; public static class Packager { - public static async Task CreatePackage(string workingDirectory, string outputDirectory, string? releaseUrl = null, string? unityPackageUrl = null, string? version = null, bool skipVcc = false, bool skipUnityPackage = false) + public static async Task CreatePackage(PackagingOptions options) { - if (skipVcc && skipUnityPackage) + if (options.SkipVcc && options.SkipUnityPackage) { Log.Information("Both skipVcc and skipUnityPackage are true, nothing to do"); return true; } - var data = GetPackageJson(workingDirectory, skipUnityPackage); + var data = GetPackageJson(options.WorkingDirectory, options.SkipUnityPackage); if (data == null) { - Log.Error("Could not find valid package.json in {WorkingDirectory}", workingDirectory); + Log.Error("Could not find valid package.json in {WorkingDirectory}", options.WorkingDirectory); return false; } + foreach (var keyValuePair in options.CustomFields) + { + data[keyValuePair.Key] = keyValuePair.Value; + } + string tempPath = Path.GetTempPath(); tempPath += "/VRLabs/Packaging"; if(Directory.Exists(tempPath)) DeleteDirectory(tempPath); Directory.CreateDirectory(tempPath); - if(!Directory.Exists(outputDirectory)) Directory.CreateDirectory(outputDirectory); + if(!Directory.Exists(options.OutputDirectory)) Directory.CreateDirectory(options.OutputDirectory); string? sha256String = null; data.Remove("zipSHA256"); string packageName = data["name"]!.ToString(); - if(!string.IsNullOrEmpty(version)) - data["version"] = version; - + if(!string.IsNullOrEmpty(options.Version)) + data["version"] = options.Version; + string packageVersion = data["version"]!.ToString(); StringBuilder githubOutput = new(); // VCC Package Creation - if (!skipVcc) + if (!options.SkipVcc) { - if(!string.IsNullOrEmpty(releaseUrl)) - data["url"] = releaseUrl; + if(!string.IsNullOrEmpty(options.ReleaseUrl)) + data["url"] = options.ReleaseUrl; - CopyDirectory(workingDirectory, tempPath, true, true); + CopyDirectory(options.WorkingDirectory, tempPath, true, true); string outputFileName = $"{packageName}-{packageVersion}.zip"; - string outputFilePath = $"{outputDirectory}/{outputFileName}"; + string outputFilePath = $"{options.OutputDirectory}/{outputFileName}"; string jsonPath = tempPath + "/package.json"; if (File.Exists(jsonPath)) @@ -70,8 +75,7 @@ public static async Task CreatePackage(string workingDirectory, string out CreateZipFile(tempPath, outputFilePath, matchedAssets.ToList()); Log.Information("Finished Zipping, available at {OutputFilePath}", outputFilePath); - if(Environment.GetEnvironmentVariable("RUNNING_ON_GITHUB_ACTIONS") is not null && - Environment.GetEnvironmentVariable("RUNNING_ON_GITHUB_ACTIONS")!.Equals("true")) + if(options.IsRunningOnGithubActions) { githubOutput.AppendLine($"vccPackagePath={outputFilePath}"); } @@ -85,20 +89,20 @@ public static async Task CreatePackage(string workingDirectory, string out } // Unity Package Creation - if (!skipUnityPackage) + if (!options.SkipUnityPackage) { string unityPackageDestinationFolder = data["unityPackageDestinationFolder"]?.ToString() ?? $"Assets/{data["name"]}"; - if (!string.IsNullOrEmpty(unityPackageUrl)) - data["unityPackageUrl"] = unityPackageUrl; + if (!string.IsNullOrEmpty(options.UnityPackageUrl)) + data["unityPackageUrl"] = options.UnityPackageUrl; var folderMetas = data["unityPackageDestinationFolderMetas"].Deserialize>(); CreateExtraFolders(tempPath, folderMetas); - CopyDirectory(workingDirectory, tempPath + "/" + unityPackageDestinationFolder, true); + CopyDirectory(options.WorkingDirectory, tempPath + "/" + unityPackageDestinationFolder, true); string outputFileName = $"{packageName}-{packageVersion}.unitypackage"; - string outputFilePath = $"{outputDirectory}/{outputFileName}"; + string outputFilePath = $"{options.OutputDirectory}/{outputFileName}"; string jsonPath = tempPath + "/" + unityPackageDestinationFolder + "/package.json"; if (File.Exists(jsonPath)) @@ -150,8 +154,7 @@ public static async Task CreatePackage(string workingDirectory, string out await packer.FlushAsync(); Log.Information("Finished Packaging, available at {OutputFilePath}", outputFilePath); - if(Environment.GetEnvironmentVariable("RUNNING_ON_GITHUB_ACTIONS") is not null && - Environment.GetEnvironmentVariable("RUNNING_ON_GITHUB_ACTIONS")!.Equals("true")) + if(options.IsRunningOnGithubActions) { githubOutput.AppendLine($"unityPackagePath={outputFilePath}"); } @@ -161,12 +164,11 @@ public static async Task CreatePackage(string workingDirectory, string out if(sha256String is not null) data["zipSHA256"] = sha256String; - var serverPackageJsonPath = $"{outputDirectory}/server-package.json"; + var serverPackageJsonPath = $"{options.OutputDirectory}/server-package.json"; await File.WriteAllTextAsync(serverPackageJsonPath, JsonSerializer.Serialize(data)); Log.Information("Finished creating server-package.json, available at {OutputFilePath}", serverPackageJsonPath); - if(Environment.GetEnvironmentVariable("RUNNING_ON_GITHUB_ACTIONS") is not null && - Environment.GetEnvironmentVariable("RUNNING_ON_GITHUB_ACTIONS")!.Equals("true")) + if(options.IsRunningOnGithubActions) { githubOutput.AppendLine($"serverPackageJsonPath={serverPackageJsonPath}"); diff --git a/VRLabs.VRCTools.Packaging/PackagingOptions.cs b/VRLabs.VRCTools.Packaging/PackagingOptions.cs new file mode 100644 index 0000000..0eb2143 --- /dev/null +++ b/VRLabs.VRCTools.Packaging/PackagingOptions.cs @@ -0,0 +1,14 @@ +namespace VRLabs.VRCTools.Packaging; + +public class PackagingOptions +{ + public required string WorkingDirectory { get; init; } + public required string OutputDirectory { get; init; } + public string? ReleaseUrl { get; init; } + public string? UnityPackageUrl { get; init; } + public string? Version { get; init; } + public bool SkipVcc { get; init; } + public bool SkipUnityPackage { get; init; } + public bool IsRunningOnGithubActions { get; init; } + public Dictionary CustomFields { get; init; } = []; +} \ No newline at end of file diff --git a/VRLabs.VRCTools.Packaging/VRLabs.VRCTools.Packaging.csproj b/VRLabs.VRCTools.Packaging/VRLabs.VRCTools.Packaging.csproj index d0f5d45..edf11c9 100644 --- a/VRLabs.VRCTools.Packaging/VRLabs.VRCTools.Packaging.csproj +++ b/VRLabs.VRCTools.Packaging/VRLabs.VRCTools.Packaging.csproj @@ -1,20 +1,21 @@ - net7.0 + net9.0 enable enable - 1.1.999 + 1.2.999 MIT VRLabs VRLabs Library that provides a way to package assets into UnityPackage and VRChat's vcc package formats + 13 - - - + + +