Skip to content

Commit 7a09d28

Browse files
💡 Allow id config as env var
1 parent 3d9ec33 commit 7a09d28

10 files changed

Lines changed: 88 additions & 29 deletions

File tree

source/GitHubAction/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ await parser.WithParsedAsync(async options =>
5656
OrgAdministerToken: options.OrgAdministerToken,
5757
GitHubRepositoryOwner: options.GitHubRepositoryOwner,
5858
OrganizationMembersGroup: options.OrganizationMembersGroup.IsEmptyOrWhitespace() ? configurationFromFile.OrganizationMembersGroup : options.OrganizationMembersGroup,
59-
CreateDeployment: options.CreateDeployment
59+
CreateDeployment: options.CreateDeployment,
60+
EmailReplaceRules: new Dictionary<string,string>()
6061
);
6162

6263
var result = await Bootstrap.StartTeamSyncAsync(renderedInput, Bootstrap.BuildInstalledFacade(renderedInput));

source/Gttsb.Core/EmailToCloudIdBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
{
33
public static class EmailToCloudIdBuilder
44
{
5-
public static IEmailToCloudIdConverter Build(string prepend, string append, IEnumerable<string> replaceString)
5+
public static IEmailToCloudIdConverter Build(string prepend, string append, IEnumerable<string> replaceString, IReadOnlyDictionary<string, string> emailReplaceRules)
66
{
7-
return new EmailToCloudIdConverter(prepend, replaceString, append);
7+
return new EmailToCloudIdConverter(prepend, replaceString, emailReplaceRules, append);
88
}
99
}
1010
}

source/Gttsb.Core/EmailToCloudIdConverter.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,40 @@ internal sealed class EmailToCloudIdConverter : IEmailToCloudIdConverter
44
{
55
private readonly string emailPrepend;
66
private readonly IEnumerable<string> itemsToReplace;
7-
private readonly string emailAppend;
7+
private readonly IReadOnlyDictionary<string, string> emailReplaceRules;
8+
private readonly string defaultEmailReplace;
89

9-
public EmailToCloudIdConverter(string emailPrepend, IEnumerable<string> itemsToReplace, string emailAppend)
10+
public EmailToCloudIdConverter(string emailPrepend, IEnumerable<string> itemsToReplace, IReadOnlyDictionary<string,string> emailReplaceRules, string defaultEmailReplace)
1011
{
1112
this.emailPrepend = emailPrepend;
1213
this.itemsToReplace = itemsToReplace;
13-
this.emailAppend = emailAppend;
14+
this.emailReplaceRules = emailReplaceRules;
15+
this.defaultEmailReplace = defaultEmailReplace;
1416
}
1517

1618
public string ToId(string email)
1719
{
20+
var splitEmail = email.Split("@");
21+
var nameComponent = splitEmail[0];
22+
var emailComponent = splitEmail[1];
23+
1824
var replaceFunctions = itemsToReplace.SelectMany(s => s.Split(";")).Select(tr => tr.Split(",")).Select<string[], Func<string, string>>(tr => (string input) =>
1925
{
2026
return input.Replace(tr[0], tr[1]);
2127
}).ToList();
2228

23-
var emailWithReplaceableItems = email;
29+
var emailWithReplaceableItems = nameComponent;
2430
foreach (var replaceFunction in replaceFunctions)
2531
{
2632
emailWithReplaceableItems = replaceFunction(emailWithReplaceableItems);
2733
}
2834

29-
return $"{emailPrepend}{emailWithReplaceableItems}{emailAppend}";
35+
if(emailReplaceRules.TryGetValue(emailComponent, out var replaceValue))
36+
{
37+
return $"{emailPrepend}{emailWithReplaceableItems}{replaceValue}";
38+
}
39+
40+
return $"{emailPrepend}{emailWithReplaceableItems}{defaultEmailReplace}";
3041
}
3142
}
3243
}

source/Gttsb.Core/GhDeployment.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ public record GhDeployment(int Id, string Org, string Repo)
55
public enum Status
66
{
77
Succeeded,
8-
Failed
8+
Failed,
9+
InProgress
910
}
1011
}
1112
}

source/Gttsb.Core/GroupSyncer.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ private async Task<GroupSyncResult> SyncronizeGroupsAsync(string gitHubOrg, IEnu
2424
if(createDeployment)
2525
{
2626
deployment = await _gitHubFacade.CreateDeploymentAsync(gitHubOrg);
27+
28+
await _gitHubFacade.UpdateDeploymentAsync(deployment, GhDeployment.Status.InProgress);
2729
}
2830

2931
var teamSyncFailures = new List<string>();

source/Gttsb.Core/RenderedInput.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public sealed record RenderedInput
1414
string OrgAdministerToken,
1515
string GitHubRepositoryOwner,
1616
string OrganizationMembersGroup,
17-
bool CreateDeployment
17+
bool CreateDeployment,
18+
IReadOnlyDictionary<string, string> EmailReplaceRules
1819
);
1920
}

source/Gttsb.Core/SyncInput.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
{
33
public sealed class SyncInput
44
{
5-
public IEnumerable<string> GitHubTeamNames { get; set; }
6-
public string EmailAppend { get; set; } = String.Empty;
7-
public IEnumerable<string> EmailTextToReplaceRules { get; set; }
8-
public string OrganizationMembersGroup { get; set; }
9-
public bool CreateDeployment { get; set; } = true;
5+
public IEnumerable<string> GitHubTeamNames { get; init; } = Enumerable.Empty<string>();
6+
public string EmailAppend { get; init; } = String.Empty;
7+
public IEnumerable<string> EmailTextToReplaceRules { get; init; } = Enumerable.Empty<string>();
8+
public string OrganizationMembersGroup { get; init; } = String.Empty;
9+
public bool CreateDeployment { get; init; } = true;
10+
public IReadOnlyDictionary<string, string> EmailReplaceRules { get; init; } = new Dictionary<string, string>();
1011
};
1112
}

source/Gttsb.Gh/AppOptions.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
{
33
public sealed class AppOptions
44
{
5-
public string PrivateKey { get; set; }
6-
public string AppId { get; set; }
5+
public string PrivateKey { get; init; }
6+
public string AppId { get; init; }
7+
public IReadOnlyDictionary<string, string> EmailReplaceRules { get; init; }
8+
public IEnumerable<string> EmailTextToReplaceRules { get; init; }
79
}
810
}

source/Gttsb.Gh/Bootstrap.cs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,12 @@ public static async Task<bool> StartTeamSyncAsync(RenderedInput inputs, IInstall
5858
var clientSecretCredential = new ClientSecretCredential(
5959
tenantId, clientId, clientSecret, options);
6060
var graphClient = new GraphServiceClient(clientSecretCredential);
61-
var activeDirectoryFacade = new ActiveDirectoryFacade(graphClient);
61+
var activeDirectoryFacade = new ActiveDirectoryFacade(graphClient);
6262

63-
var emailToCloudIdBuilder = EmailToCloudIdBuilder.Build(emailPrepend, emailAppend, itemsToReplace);
63+
var emailReplaceRules = GetEmailReplaceRules(inputs.EmailReplaceRules);
64+
var itemsToReplaceRules = GetItemsToReplaceRules(Enumerable.Empty<string>());
65+
66+
var emailToCloudIdBuilder = EmailToCloudIdBuilder.Build(string.Empty, inputs.EmailAppend, itemsToReplaceRules, emailReplaceRules);
6467

6568
var groupSyncer = GroupSyncerBuilder.Build(activeDirectoryFacade, gitHubFacade, emailToCloudIdBuilder);
6669

@@ -108,11 +111,12 @@ public static async Task<bool> StartTeamSyncAsync(IActiveDirectoryFacade activeD
108111
// Azure AD Group and GitHub Team Name must match (my opinion, baked into this tool)
109112
var groupDisplayNames = inputs.GitHubTeamNames.Concat(new[] { inputs.OrganizationMembersGroup }).Distinct().ToDictionary(t => t);
110113

111-
var org = gitHubFacade.OrgName;
112-
113-
var itemsToReplace = inputs.EmailTextToReplaceRules;
114+
var org = gitHubFacade.OrgName;
115+
116+
var emailReplaceRules = GetEmailReplaceRules(inputs.EmailReplaceRules);
117+
var itemsToReplaceRules = GetItemsToReplaceRules(inputs.EmailTextToReplaceRules);
114118

115-
var emailToCloudIdBuilder = EmailToCloudIdBuilder.Build(string.Empty, inputs.EmailAppend, itemsToReplace);
119+
var emailToCloudIdBuilder = EmailToCloudIdBuilder.Build(string.Empty, inputs.EmailAppend, itemsToReplaceRules, emailReplaceRules);
116120

117121
var groupSyncer = GroupSyncerBuilder.Build(activeDirectoryFacade, gitHubFacade, emailToCloudIdBuilder);
118122

@@ -147,6 +151,26 @@ public static async Task<bool> StartTeamSyncAsync(IActiveDirectoryFacade activeD
147151
return true;
148152
}
149153

154+
private static IEnumerable<string> GetItemsToReplaceRules(IEnumerable<string> emailTextToReplaceRules)
155+
{
156+
// TODO: use proper config fetching here...
157+
var fromEnvAsString = Environment.GetEnvironmentVariable("EmailTextToReplaceRules") ?? "{}";
158+
159+
var fromEnv = JsonConvert.DeserializeObject<IEnumerable<string>>(fromEnvAsString) ?? Enumerable.Empty<string>();
160+
161+
return emailTextToReplaceRules.Any() ? emailTextToReplaceRules : fromEnv;
162+
}
163+
164+
private static IReadOnlyDictionary<string, string> GetEmailReplaceRules(IReadOnlyDictionary<string, string> emailReplaceRules)
165+
{
166+
// TODO: use proper config fetching here...
167+
var fromEnvAsString = Environment.GetEnvironmentVariable("EmailReplaceRules") ?? "{}";
168+
169+
var fromEnv = JsonConvert.DeserializeObject<IReadOnlyDictionary<string, string>>(fromEnvAsString) ?? new Dictionary<string,string>();
170+
171+
return emailReplaceRules.Any() ? emailReplaceRules : fromEnv;
172+
}
173+
150174
static void WriteConsoleOutput(ISet<GitHubUser> usersWithSyncIssues)
151175
{
152176
if (usersWithSyncIssues.Any())

source/Gttsb.Gh/InstalledGitHubFacade.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ public sealed partial class InstalledGitHubFacade : IInstalledGitHubFacade
99
{
1010
private readonly GitHubClient gitHubClient;
1111

12-
public string OrgName { get; }
12+
public string OrgName { get; }
1313

1414
public InstalledGitHubFacade(GitHubClient gitHubClient, string orgName)
1515
{
1616
this.gitHubClient = gitHubClient;
17-
OrgName = orgName;
17+
OrgName = orgName;
1818
}
1919

2020
public async Task<OperationResponse> AddOrgMemberAsync(string gitHubOrg, ValidGitHubId gitHubId)
@@ -123,22 +123,38 @@ public async Task<GhDeployment> CreateDeploymentAsync(string gitHubOrg)
123123
// TODO: update NewDeployment to use the actual commit sha that was used in this sync
124124
var deployment = await gitHubClient.Repository.Deployment.Create(gitHubOrg, repo, new NewDeployment("main")
125125
{
126-
Environment = "GitHub Teams Sync"
126+
Environment = "GitHub Teams Sync"
127127
});
128128

129129
return new GhDeployment(deployment.Id, gitHubOrg, repo);
130130
}
131131

132132
public async Task UpdateDeploymentAsync(GhDeployment deployment, GhDeployment.Status status)
133133
{
134-
var mappedStatus = status == GhDeployment.Status.Succeeded ? DeploymentState.Success : DeploymentState.Failure;
134+
DeploymentState mappedStatus = MapStatus(status);
135135

136136
await gitHubClient.Repository.Deployment.Status.Create(deployment.Org, deployment.Repo, deployment.Id, new NewDeploymentStatus(mappedStatus)
137137
{
138-
Description = "Teams have been synced!"
138+
Description = "Teams have been synced! Please see the logs for more details.",
139+
LogUrl = "https://example.com"
139140
});
140141
}
141142

143+
private static DeploymentState MapStatus(GhDeployment.Status status)
144+
{
145+
switch (status)
146+
{
147+
case GhDeployment.Status.Succeeded:
148+
return DeploymentState.Success;
149+
case GhDeployment.Status.Failed:
150+
return DeploymentState.Failure;
151+
case GhDeployment.Status.InProgress:
152+
return DeploymentState.InProgress;
153+
}
154+
155+
throw new Exception("Invalid status");
156+
}
157+
142158
public async Task<SyncInput> GetConfigurationForInstallationAsync()
143159
{
144160
var files = await gitHubClient.Repository.Content.GetAllContents(this.OrgName, ".github");
@@ -152,7 +168,7 @@ public async Task<SyncInput> GetConfigurationForInstallationAsync()
152168
var configurationAsString = System.Text.Encoding.Default.GetString(configurationContent);
153169

154170
var deserializer = new DeserializerBuilder().Build();
155-
var yamlObject = deserializer.Deserialize<SyncInput>(configurationAsString);
171+
var yamlObject = deserializer.Deserialize<SyncInput>(configurationAsString);
156172

157173
return yamlObject;
158174
}

0 commit comments

Comments
 (0)