Skip to content

Commit d87afb5

Browse files
rob1997robGG1997
andauthored
Release CI (#1195)
* Revert "automated duplicating imported samples modifications (#595)" This reverts commit a555894. * made main package testable, revert due to a mistake * initial commit to test CI * path updated * path updated for linux * Packages version changes implemented * Program renamed to Setup * checkpoint before testing git * git push added * proper logging * more log check * more log test * powershell added * added missing command line argument * reverted to run with bash * removed powershell package * exception support * configure and push added * deploy key added for push * bad substitution fix * github env vars setup * checkpoint * tags and dependency version changes * manual workflow and release added * release version from input * cool-er title for release workflow * Ignore serialization only, on some Package properties * removed unused using statement * documentation added --------- Co-authored-by: robGG1997 <[email protected]>
1 parent 4b554b5 commit d87afb5

File tree

11 files changed

+432
-0
lines changed

11 files changed

+432
-0
lines changed

.github/workflows/release.yaml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Release ⬆️
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: 'Version to Release'
8+
required: true
9+
release_notes:
10+
description: 'Version Release Notes'
11+
required: true
12+
13+
env:
14+
git_email: "${{ github.actor }}@users.noreply.github.com"
15+
git_actor: "${{ github.actor }}"
16+
17+
jobs:
18+
setup:
19+
name: Setup job
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
with:
25+
lfs: true
26+
ssh-key: ${{ secrets.DEPLOY_KEY }}
27+
28+
- name: Setup .NET
29+
uses: actions/setup-dotnet@v3
30+
with:
31+
dotnet-version: 8.0.x
32+
33+
- name: Run
34+
run: |
35+
cd Setup
36+
dotnet run -release:${{ github.event.inputs.version }} Setup/Setup.csproj
37+
- name: Create Release
38+
id: create_release
39+
uses: actions/create-release@v1
40+
env:
41+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42+
with:
43+
tag_name: ${{ github.event.inputs.version }}
44+
release_name: Release ${{ github.event.inputs.version }}
45+
body: |
46+
${{ github.event.inputs.release_notes }}
47+
draft: false
48+
prerelease: false

Setup/Git.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Setup.Utils;
2+
3+
namespace Setup;
4+
5+
/// <summary>
6+
/// Git helper class.
7+
/// </summary>
8+
public static class Git
9+
{
10+
private static bool _configured;
11+
12+
public static void Add(string path)
13+
{
14+
$"git add \"{path}\" -f".RunWithBash();
15+
}
16+
17+
public static void Commit(string message, string[] tags = null)
18+
{
19+
if (!_configured)
20+
{
21+
Configure();
22+
}
23+
24+
$"git commit -m \"{message} [skip ci]\"".RunWithBash();
25+
26+
if (tags != null)
27+
{
28+
foreach (var tag in tags)
29+
{
30+
if (!string.IsNullOrEmpty(tag))
31+
{
32+
Tag(tag);
33+
}
34+
}
35+
}
36+
}
37+
38+
public static void Push(string[] tags = null)
39+
{
40+
"git push -f".RunWithBash();
41+
42+
if (tags != null)
43+
{
44+
foreach (string tag in tags)
45+
{
46+
if (!string.IsNullOrEmpty(tag))
47+
{
48+
$"git push origin \"{tag}\"".RunWithBash();
49+
}
50+
}
51+
}
52+
}
53+
54+
public static void CommitAndPush(string message, string[] tags = null)
55+
{
56+
Commit(message, tags);
57+
58+
Push(tags);
59+
}
60+
61+
public static void Tag(string tag)
62+
{
63+
$"git tag \"{tag}\"".RunWithBash();
64+
}
65+
66+
private static void Configure()
67+
{
68+
"git config user.email $git_email".RunWithBash();
69+
"git config user.name $git_actor".RunWithBash();
70+
71+
_configured = true;
72+
}
73+
}

Setup/Package.cs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using Newtonsoft.Json;
6+
using Newtonsoft.Json.Linq;
7+
using Setup.Utils;
8+
9+
namespace Setup
10+
{
11+
/// <summary>
12+
/// Unity package.json model for UPM.
13+
/// https://docs.unity3d.com/Manual/upm-manifestPkg.html.
14+
/// </summary>
15+
public class Package
16+
{
17+
/// <summary>
18+
/// Path of package from root of repository.
19+
/// </summary>
20+
[JsonIgnore]
21+
public string Path { get; private set; }
22+
23+
[JsonProperty("name"), JsonIgnoreSerialization]
24+
public string Name { get; private set; }
25+
26+
[JsonProperty("version")]
27+
public string Version { get; private set; }
28+
29+
[JsonProperty("dependencies", NullValueHandling = NullValueHandling.Ignore)]
30+
public Dictionary<string, string> Dependencies { get; private set; }
31+
32+
[JsonProperty("testables", NullValueHandling = NullValueHandling.Ignore), JsonIgnoreSerialization]
33+
public string[] Testables { get; private set; }
34+
35+
[JsonProperty("samples", NullValueHandling = NullValueHandling.Ignore), JsonIgnoreSerialization]
36+
public Sample[] Samples { get; private set; }
37+
38+
// For Json Deserialize.
39+
public Package()
40+
{
41+
42+
}
43+
44+
public Package(string path)
45+
{
46+
Path = path;
47+
}
48+
49+
/// <summary>
50+
/// Sets Package Version.
51+
/// </summary>
52+
/// <param name="version">Version string.</param>
53+
/// <exception cref="Exception">Exception thrown if version format doesn't match guidelines https://semver.org/.</exception>
54+
public void SetVersion(string version)
55+
{
56+
string[] increments = version.Split('.');
57+
58+
if (increments.Length != 3
59+
|| !increments.Any(i => int.TryParse(i, out _)
60+
|| int.Parse(i) < 0
61+
|| int.Parse(i) > 9))
62+
{
63+
throw new Exception("Incorrect Version Format https://semver.org/");
64+
}
65+
66+
Version = version;
67+
68+
string[] keys = Dependencies.Where(d => Setup.Packages.Any(p => p.Name == d.Key))
69+
.Select(d => d.Key)
70+
.ToArray();
71+
72+
foreach (string key in keys)
73+
{
74+
Dependencies[key] = version;
75+
}
76+
}
77+
78+
/// <summary>
79+
/// Save altered package to <see cref="Path"/>.
80+
/// </summary>
81+
public void Save()
82+
{
83+
string json = File.ReadAllText(Path);
84+
85+
JObject jObject = JObject.Parse(json);
86+
87+
jObject.Merge(
88+
JObject.Parse(JsonConvert.SerializeObject(this,
89+
new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() })),
90+
new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Merge });
91+
92+
File.WriteAllText(Path, jObject.ToString(Formatting.Indented));
93+
}
94+
}
95+
96+
public struct Sample
97+
{
98+
[JsonProperty("path")]
99+
public string Path { get; private set; }
100+
}
101+
}

Setup/Release.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Collections.Generic;
2+
3+
namespace Setup;
4+
5+
/// <summary>
6+
/// Release.
7+
/// </summary>
8+
public class Release
9+
{
10+
private readonly Package[] _packages;
11+
12+
private readonly string _version;
13+
14+
public Release(string version)
15+
{
16+
_packages = Setup.Packages.ToArray();
17+
18+
_version = version;
19+
}
20+
21+
/// <summary>
22+
/// Bumps the version and makes a release.
23+
/// Commit and push with package.json versions bumped.
24+
/// Tag the commits so another CI (open-upm) can pick them up.
25+
/// </summary>
26+
public void Run()
27+
{
28+
List<string> tags = new List<string>();
29+
30+
tags.Add(_version);
31+
32+
foreach (Package package in _packages)
33+
{
34+
package.SetVersion(_version);
35+
36+
package.Save();
37+
38+
Git.Add(package.Path);
39+
40+
tags.Add($"{package.Name}/{_version}");
41+
}
42+
43+
Git.CommitAndPush($"Release {_version}", tags.ToArray());
44+
}
45+
}

Setup/Setup.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using Newtonsoft.Json;
4+
5+
namespace Setup
6+
{
7+
internal class Setup
8+
{
9+
public static readonly List<Package> Packages = new List<Package>();
10+
11+
// dotnet run -release:3.0.0 -duplicate_samples -publish_dependencies;
12+
static void Main(string[] args)
13+
{
14+
// Initialize packages from file.
15+
string json = File.ReadAllText("packages.json");
16+
17+
string[] paths = JsonConvert.DeserializeObject<string[]>(json);
18+
19+
for (int i = 0; i < paths.Length; i++)
20+
{
21+
string path = $"../{paths[i]}";
22+
23+
Package package = new Package(path);
24+
25+
JsonConvert.PopulateObject(File.ReadAllText(path), package);
26+
27+
Packages.Add(package);
28+
}
29+
30+
// Parse arguments and Run operations based on that.
31+
// TODO: use runnable and runner to run multiple operations sort orders.
32+
foreach (var arg in args)
33+
{
34+
switch (arg)
35+
{
36+
case not null when arg.StartsWith("-release"):
37+
38+
string version = arg.Split(":")[1];
39+
40+
Release release = new Release(version);
41+
42+
release.Run();
43+
44+
break;
45+
}
46+
}
47+
}
48+
}
49+
}

Setup/Setup.csproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<OutputType>Exe</OutputType>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
10+
</ItemGroup>
11+
12+
</Project>

Setup/Setup.sln

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Setup", "Setup.csproj", "{9EE36F23-7E56-4398-B7DE-E683097CE49F}"
4+
EndProject
5+
Global
6+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7+
Debug|Any CPU = Debug|Any CPU
8+
Release|Any CPU = Release|Any CPU
9+
EndGlobalSection
10+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
11+
{9EE36F23-7E56-4398-B7DE-E683097CE49F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
12+
{9EE36F23-7E56-4398-B7DE-E683097CE49F}.Debug|Any CPU.Build.0 = Debug|Any CPU
13+
{9EE36F23-7E56-4398-B7DE-E683097CE49F}.Release|Any CPU.ActiveCfg = Release|Any CPU
14+
{9EE36F23-7E56-4398-B7DE-E683097CE49F}.Release|Any CPU.Build.0 = Release|Any CPU
15+
EndGlobalSection
16+
EndGlobal
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace Setup.Utils;
4+
5+
/// <summary>
6+
/// Fir ignoring serialization of a property.
7+
/// Deserialization still works.
8+
/// </summary>
9+
[AttributeUsage(AttributeTargets.Property)]
10+
public class JsonIgnoreSerializationAttribute : Attribute
11+
{
12+
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using Newtonsoft.Json.Serialization;
6+
7+
namespace Setup.Utils;
8+
9+
/// <summary>
10+
/// Resolver for custom serialization.
11+
/// </summary>
12+
public class JsonPropertiesResolver : DefaultContractResolver
13+
{
14+
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
15+
{
16+
//Return properties that do NOT have the JsonIgnoreSerializationAttribute
17+
return objectType.GetProperties()
18+
.Where(pi => !Attribute.IsDefined(pi, typeof(JsonIgnoreSerializationAttribute)))
19+
.ToList<MemberInfo>();
20+
}
21+
}

0 commit comments

Comments
 (0)