package com.hubspot.blazar.command; import java.io.FileNotFoundException; import java.io.IOException; import net.sourceforge.argparse4j.inf.Namespace; import org.kohsuke.github.GHRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.hubspot.blazar.base.GitInfo; import com.hubspot.blazar.config.BlazarConfiguration; import com.hubspot.blazar.config.GitHubConfiguration; import com.hubspot.blazar.data.service.BranchService; import com.hubspot.blazar.util.GitHubHelper; import io.dropwizard.setup.Bootstrap; /** * GitHub repositories can change owners and names, and be deleted without Blazar * getting an event to update its metadata. Because we don't receive events this * cleaner is run against all repos periodically to ensure that we delete anything * that has been deleted or moved to a non-managed organization. * * @see CleanRepoMetadataCommand#run(Bootstrap, Namespace, BlazarConfiguration) * for the DropWizard command * <p> * This runnable checks GitHub for the current metadata about a single repository * If the information is different from what Blazar knows we update that * information accordingly: * <p> * - If the repository does not exist, we delete it. * - If the repository name has changed, we update it. * - If the organization name has changed, we update it. * - If the organization name is not a managed organization, we delete it. */ public class GitBranchUpdater implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(GitBranchUpdater.class); private final GitHubHelper gitHubHelper; private final BlazarConfiguration configuration; private final BranchService branchService; private boolean noopMode; private final GitInfo oldBranch; public GitBranchUpdater(GitInfo oldBranch, GitHubHelper gitHubHelper, BlazarConfiguration configuration, BranchService branchService, boolean noopMode) { this.oldBranch = oldBranch; this.gitHubHelper = gitHubHelper; this.configuration = configuration; this.branchService = branchService; this.noopMode = noopMode; } @Override public void run() { if (!configuration.getGitHubConfiguration().containsKey(oldBranch.getHost())) { LOG.warn("No git host configured for {}/{}#{} marking as inactive", oldBranch.getHost(), oldBranch.getFullRepositoryName(), oldBranch.getBranch()); deleteBranch(oldBranch); return; } GitHubConfiguration githubConfiguration = configuration.getGitHubConfiguration().get(oldBranch.getHost()); GHRepository ghRepository; try { ghRepository = gitHubHelper.repositoryFor(oldBranch); } catch (IOException e) { if (e instanceof FileNotFoundException) { LOG.info("Deleting branch {} because its not found in GitHub", oldBranch); deleteBranch(oldBranch); return; } LOG.error("Caught exception while trying to find {} in github", oldBranch, e); throw new RuntimeException(e); } if (ghRepository.getId() != oldBranch.getRepositoryId()) { LOG.warn("A repository with a different github id {} has replaced {}. Considering {}#{} as deleted ", ghRepository.getId(), oldBranch, oldBranch.getFullRepositoryName(), oldBranch.getBranch()); deleteBranch(oldBranch); return; } String oldRepoOrg = oldBranch.getOrganization(); String oldRepoName = oldBranch.getRepository(); String newRepoName = ghRepository.getName(); String newRepoOrg = ghRepository.getOwnerName(); // Whether we listen & process updates for repos in this org boolean orgIsConfigured = githubConfiguration.getOrganizations().contains(newRepoOrg); boolean orgNameChanged = !oldRepoOrg.equals(newRepoOrg); boolean repoNameChanged = !oldRepoName.equals(newRepoName); // Only update a branch if it has changed. if (orgNameChanged || repoNameChanged || !orgIsConfigured) { boolean active = orgIsConfigured; GitInfo updatedBranch = updateBranch(oldBranch, newRepoOrg, newRepoName, active); LOG.info("Branch {} has changed updating to {}", oldBranch, updatedBranch); if (noopMode) { LOG.info("Not Updating {} -- running in noop mode", updatedBranch); } else { branchService.upsert(updatedBranch); } } } private void deleteBranch(GitInfo branch) { if (noopMode) { LOG.info("Not Deleting {} -- running in noop mode", branch); } else { branchService.deactivate(branch); } } private GitInfo updateBranch(GitInfo branch, String realRepoOrg, String realRepoName, boolean active) { return new GitInfo(branch.getId(), branch.getHost(), realRepoOrg, realRepoName, branch.getRepositoryId(), branch.getBranch(), active, branch.getCreatedTimestamp(), System.currentTimeMillis()); } }