Skip to content

Commit

Permalink
♻️ rename; separate membership application events
Browse files Browse the repository at this point in the history
  • Loading branch information
ebullient committed Aug 13, 2024
1 parent 7b65457 commit 6f9a109
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ protected CommonhausUser getUser() {
}

CommonhausUser updateHasDefaultFlag(CommonhausUser user) {
// eventual consistency. No big deal if this
CommonhausUser result = datastore.setCommonhausUser(new UpdateEvent(user,
(c, u) -> {
u.services().forwardEmail().hasDefaultAlias = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum MemberStatus {
INACTIVE,
PENDING,
SPONSOR,
CONTRIBUTOR, // project contributor, not sponsor or member
UNKNOWN;

public static MemberStatus fromString(String role) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import java.util.List;
import java.util.Objects;

import org.commonhaus.automation.admin.github.InstallationAccess;
import org.commonhaus.automation.admin.github.InstallationContext;
import org.commonhaus.automation.github.context.QueryContext;

import io.quarkus.runtime.annotations.RegisterForReflection;
Expand Down Expand Up @@ -70,7 +70,7 @@ public int hashCode() {
*
* @param access the installation access object
*/
public void setAccess(InstallationAccess access) {
public void setAccess(InstallationContext access) {
sources.forEach(source -> {
// we should have (at least) read access to the source repo
access.add(source.repo());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,16 @@

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.json.JsonObject;

import org.commonhaus.automation.admin.api.MemberApplicationProcess;
import org.commonhaus.automation.admin.api.MembershipApplicationData;
import org.commonhaus.automation.admin.config.UserManagementConfig.AttestationConfig;
import org.commonhaus.automation.github.context.ActionType;
import org.commonhaus.automation.github.context.DataCommonComment;
import org.commonhaus.automation.github.context.DataCommonItem;
import org.commonhaus.automation.github.context.DataLabel;
import org.commonhaus.automation.github.context.JsonAttribute;
import org.kohsuke.github.GHEventPayload;
import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;

import io.quarkiverse.githubapp.GitHubEvent;
import io.quarkiverse.githubapp.event.Issue;
import io.quarkiverse.githubapp.event.IssueComment;
import io.quarkiverse.githubapp.event.Label;
import io.quarkiverse.githubapp.event.Membership;
import io.quarkiverse.githubapp.event.Push;
Expand All @@ -34,9 +26,6 @@ public class AdminGitHubEvents {
@Inject
AppContextService ctx;

@Inject
MemberApplicationProcess applicationProcess;

public void updateAttestationList(GitHub github, DynamicGraphQLClient graphQLClient,
@Push GHEventPayload.Push eventPayload) {
long installationId = eventPayload.getInstallation().getId();
Expand Down Expand Up @@ -87,91 +76,6 @@ public void updateMembership(GitHub github, DynamicGraphQLClient graphQLClient,
qc.updateTeamList(eventPayload.getOrganization(), eventPayload.getTeam());
}

/**
* Called when an issue is labeled
*
* @param event
* @param github
* @param graphQLClient
* @param eventPayload
*/
public void applicationIssueLabelAdded(GitHubEvent event, GitHub github, DynamicGraphQLClient graphQLClient,
@Issue.Labeled GHEventPayload.Issue eventPayload) {
long installationId = eventPayload.getInstallation().getId();
String repoFullName = eventPayload.getRepository().getFullName();
Log.debugf("[%s] applicationIssueLabelAdded: %s",
installationId, repoFullName);

ActionType actionType = ActionType.fromString(event.getAction());
JsonObject data = JsonAttribute.unpack(event.getPayload());
DataCommonItem issue = JsonAttribute.issue.commonItemFrom(data);
DataLabel label = JsonAttribute.label.labelFrom(data);

// ignore if it isn't an issue in the datastore repository
if (!repoFullName.equals(ctx.getDataStore())
|| !MembershipApplicationData.isMemberApplicationEvent(issue, label)) {
return;
}

ScopedQueryContext qc = ctx.refreshScopedQueryContext(
installationId,
eventPayload.getRepository())
.addExisting(graphQLClient)
.addExisting(github);

Log.debugf("[%s] applicationIssueLabelAdded #%s - %s", qc.getLogId(),
issue.number, actionType);

try {
qc.getLabels(qc.getRepositoryId()); // pre-fetch
applicationProcess.handleApplicationLabelAdded(qc, eventPayload.getIssue(), issue, label);
} catch (Throwable e) {
qc.logAndSendEmail("Error with issue label event", e);
} finally {
qc.clearErrors();
}
}

/**
* Called when there is a comment event on an issue.
*
* @param event
* @param github
* @param graphQLClient
* @param eventPayload
*/
public void updateApplicationComments(GitHubEvent event, GitHub github, DynamicGraphQLClient graphQLClient,
@IssueComment GHEventPayload.IssueComment eventPayload) {
long installationId = eventPayload.getInstallation().getId();
String repoFullName = eventPayload.getRepository().getFullName();
Log.debugf("[%s] updateApplicationComments: %s",
installationId, repoFullName);

JsonObject data = JsonAttribute.unpack(event.getPayload());
DataCommonItem issue = JsonAttribute.issue.commonItemFrom(data);

// ignore if it isn't an issue in the datastore repository
if (!repoFullName.equals(ctx.getDataStore())
|| !MembershipApplicationData.isMemberApplicationEvent(issue, null)) {
return;
}

ScopedQueryContext qc = ctx.refreshScopedQueryContext(
eventPayload.getInstallation().getId(),
eventPayload.getRepository())
.addExisting(github)
.addExisting(graphQLClient);

DataCommonComment comment = JsonAttribute.comment.commonCommentFrom(data);
try {
applicationProcess.handleApplicationComment(qc, issue, comment);
} catch (Exception e) {
qc.logAndSendEmail("Error with issue label event", e);
} finally {
qc.clearErrors();
}
}

/**
* Called when there is a label change (added or removed from the repository)
* event.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public class AppContextService extends BaseContextService {
// for the access we need across multiple installations to construct
// query contexts with the necessary permissions to modify team membership
// or manage membership-related issues/user records.
final Map<Long, InstallationAccess> installationAccess = new ConcurrentHashMap<>();
final Map<Long, InstallationContext> installationAccess = new ConcurrentHashMap<>();
final Map<String, Long> writeToInstallId = new ConcurrentHashMap<>();
final Map<String, Long> readToInstallId = new ConcurrentHashMap<>();

Expand Down Expand Up @@ -115,7 +115,7 @@ public ScopedQueryContext getScopedQueryContext(String scope) {
Log.errorf("No installation found for %s", scope);
return null;
}
InstallationAccess access = installationAccess.get(installationId);
InstallationContext access = installationAccess.get(installationId);
return access.containsRepo(scope)
? new ScopedQueryContext(this, installationId, orgName, scope)
: new ScopedQueryContext(this, installationId, orgName, null);
Expand All @@ -141,8 +141,8 @@ protected void repositoryDiscovered(@Observes RepositoryDiscoveryEvent repoEvent
Optional<AdminConfigFile> repoConfig = repoEvent.getRepositoryConfig();

if (action.added()) {
InstallationAccess access = installationAccess.computeIfAbsent(installationId,
k -> new InstallationAccess(installationId, orgName));
InstallationContext access = installationAccess.computeIfAbsent(installationId,
k -> new InstallationContext(installationId, orgName));
access.write.add(repoFullName);
access.write.add(orgName);

Expand All @@ -163,7 +163,7 @@ protected void repositoryDiscovered(@Observes RepositoryDiscoveryEvent repoEvent
userConfig = UserManagementConfig.DISABLED;
}

InstallationAccess access = installationAccess.get(installationId);
InstallationContext access = installationAccess.get(installationId);
if (action.installation()) {
// Installation is removed, forget all access
access = installationAccess.remove(installationId);
Expand Down Expand Up @@ -193,7 +193,7 @@ protected void repositoryDiscovered(@Observes RepositoryDiscoveryEvent repoEvent
* May return null if connection can not be established
*
* @param nodeId User Node ID
* @param object Security Identity
* @param identity Security Identity
* @return GitHub connection or null
* @throws IOException
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ public CommonhausUser getCommonhausUser(String login, long id, boolean resetCach
/**
* Update Commonhaus user data
*
* @param user Commonhaus user object
* @param message Commit message
* @param updateEvent Update message containing the user and commit message
*
* @throws RuntimeException if GitHub or other API query fails
*/
Expand Down Expand Up @@ -339,8 +338,4 @@ public static String getKey(QueryEvent event) {
public static String getKey(CommonhausUser user) {
return user.login() + ":" + user.id();
}

public static String getKey(MemberSession session) {
return session.login() + ":" + session.nodeId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
* The bot is installed requires a certain set of permissions, which means it will be
* able to read/write any repository that is associated with its own org.
*/
public class InstallationAccess {
public class InstallationContext {
final long installationId;
final String orgName;
final Set<String> write = new HashSet<>();
final Set<String> read = new HashSet<>();

InstallationAccess(long installationId, String orgName) {
InstallationContext(long installationId, String orgName) {
this.installationId = installationId;
this.orgName = orgName;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package org.commonhaus.automation.admin.github;

import jakarta.inject.Inject;
import jakarta.json.JsonObject;

import org.commonhaus.automation.admin.api.MemberApplicationProcess;
import org.commonhaus.automation.admin.api.MembershipApplicationData;
import org.commonhaus.automation.github.context.ActionType;
import org.commonhaus.automation.github.context.DataCommonComment;
import org.commonhaus.automation.github.context.DataCommonItem;
import org.commonhaus.automation.github.context.DataLabel;
import org.commonhaus.automation.github.context.JsonAttribute;
import org.kohsuke.github.GHEventPayload;
import org.kohsuke.github.GitHub;

import io.quarkiverse.githubapp.GitHubEvent;
import io.quarkiverse.githubapp.event.Issue;
import io.quarkiverse.githubapp.event.IssueComment;
import io.quarkus.logging.Log;
import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClient;

public class MembershipGithubEvents {

@Inject
AppContextService ctx;

@Inject
MemberApplicationProcess applicationProcess;

/**
* Called when an issue is labeled
*
* @param event
* @param github
* @param graphQLClient
* @param eventPayload
*/
public void applicationIssueLabelAdded(GitHubEvent event, GitHub github, DynamicGraphQLClient graphQLClient,
@Issue.Labeled GHEventPayload.Issue eventPayload) {
long installationId = eventPayload.getInstallation().getId();
String repoFullName = eventPayload.getRepository().getFullName();
Log.debugf("[%s] applicationIssueLabelAdded: %s",
installationId, repoFullName);

ActionType actionType = ActionType.fromString(event.getAction());
JsonObject data = JsonAttribute.unpack(event.getPayload());
DataCommonItem issue = JsonAttribute.issue.commonItemFrom(data);
DataLabel label = JsonAttribute.label.labelFrom(data);

// ignore if it isn't an issue in the datastore repository
if (!repoFullName.equals(ctx.getDataStore())
|| !MembershipApplicationData.isMemberApplicationEvent(issue, label)) {
return;
}

ScopedQueryContext qc = ctx.refreshScopedQueryContext(
installationId,
eventPayload.getRepository())
.addExisting(graphQLClient)
.addExisting(github);

Log.debugf("[%s] applicationIssueLabelAdded #%s - %s", qc.getLogId(),
issue.number, actionType);

try {
qc.getLabels(qc.getRepositoryId()); // pre-fetch
applicationProcess.handleApplicationLabelAdded(qc, eventPayload.getIssue(), issue, label);
} catch (Throwable e) {
qc.logAndSendEmail("Error with issue label event", e);
} finally {
qc.clearErrors();
}
}

/**
* Called when there is a comment event on an issue.
*
* @param event
* @param github
* @param graphQLClient
* @param eventPayload
*/
public void updateApplicationComments(GitHubEvent event, GitHub github, DynamicGraphQLClient graphQLClient,
@IssueComment GHEventPayload.IssueComment eventPayload) {
long installationId = eventPayload.getInstallation().getId();
String repoFullName = eventPayload.getRepository().getFullName();
Log.debugf("[%s] updateApplicationComments: %s",
installationId, repoFullName);

JsonObject data = JsonAttribute.unpack(event.getPayload());
DataCommonItem issue = JsonAttribute.issue.commonItemFrom(data);

// ignore if it isn't an issue in the datastore repository
if (!repoFullName.equals(ctx.getDataStore())
|| !MembershipApplicationData.isMemberApplicationEvent(issue, null)) {
return;
}

ScopedQueryContext qc = ctx.refreshScopedQueryContext(
eventPayload.getInstallation().getId(),
eventPayload.getRepository())
.addExisting(github)
.addExisting(graphQLClient);

DataCommonComment comment = JsonAttribute.comment.commonCommentFrom(data);
try {
applicationProcess.handleApplicationComment(qc, issue, comment);
} catch (Exception e) {
qc.logAndSendEmail("Error with issue label event", e);
} finally {
qc.clearErrors();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ public void postBootstrapDiscovery(@Observes BootstrapDiscoveryEvent postEvent)
}
}

/**
* Push event
* If the pushed file matches the configuration file, re-read the configuration and update the team members.
*/
public void updateTeamMembers(GitHubEvent event, GitHub github, DynamicGraphQLClient graphQLClient,
@Push GHEventPayload.Push pushEvent) {
GHRepository repo = pushEvent.getRepository();
Expand Down

0 comments on commit 6f9a109

Please sign in to comment.