예제 #1
0
        public async Task <string> GetTokenForInstallationAsync(long installationId)
        {
            if (TryGetCachedToken(installationId, out AccessToken cachedToken))
            {
                _logger.LogInformation($"Cached token obtained for GitHub installation {installationId}. Expires at {cachedToken.ExpiresAt}.");
                return(cachedToken.Token);
            }

            return(await _retry.RetryAsync(
                       async() =>
            {
                string jwt = _tokens.GetAppToken();
                var appClient = new Octokit.GitHubClient(_gitHubClientOptions.Value.ProductHeader)
                {
                    Credentials = new Credentials(jwt, AuthenticationType.Bearer)
                };
                AccessToken token = await appClient.GitHubApps.CreateInstallationToken(installationId);
                _logger.LogInformation($"New token obtained for GitHub installation {installationId}. Expires at {token.ExpiresAt}.");
                UpdateTokenCache(installationId, token);
                return token.Token;
            },
                       ex => _logger.LogError(ex, $"Failed to get a github token for installation id {installationId}, retrying"),
                       ex => ex is ApiException && ((ApiException)ex).StatusCode == HttpStatusCode.InternalServerError));
        }
        public async Task <long> GetInstallationId(string repositoryUrl)
        {
            string[] segments = new Uri(repositoryUrl, UriKind.Absolute).Segments;
            string   org      = segments[segments.Length - 2].TrimEnd('/').ToLowerInvariant();

            if (HasCachedValue(org, out long installation))
            {
                return(installation);
            }

            await _sem.WaitAsync();

            try
            {
                if (HasCachedValue(org, out installation))
                {
                    return(installation);
                }

                _log.LogInformation("No cached installation token found for {org}", org);

                ImmutableDictionary <string, long> .Builder newCache = ImmutableDictionary.CreateBuilder <string, long>();
                string appToken = _tokens.GetAppToken();
                var    client   = new GitHubAppsClient(
                    new ApiConnection(
                        new Connection(_options.Value.ProductHeader)
                {
                    Credentials = new Credentials(appToken, AuthenticationType.Bearer)
                }
                        )
                    );

                foreach (Installation i in await client.GetAllInstallationsForCurrent())
                {
                    string installedOrg = i.Account.Login.ToLowerInvariant();
                    _log.LogInformation("Found installation token for {org}, with id {id}", installedOrg, i.Id);
                    newCache.Add(installedOrg, i.Id);
                }

                foreach (string key in _cache.Keys)
                {
                    // Anything we had before but don't have now has been uninstalled, remove it
                    if (newCache.TryAdd(key, 0))
                    {
                        _log.LogInformation("Removed uninstalled org {org}", key);
                    }
                }

                // If the current thing wasn't in this list, it's not installed, record that so when they ask again in
                // a few seconds, we don't have to re-query GitHub
                if (newCache.TryAdd(org, 0))
                {
                    _log.LogInformation("Removed uninstalled, but requested org {org}", org);
                }

                Interlocked.Exchange(ref _cache, newCache.ToImmutable());
                _lastCached = DateTimeOffset.UtcNow;

                return(_cache[org]);
            }
            finally
            {
                _sem.Release();
            }
        }