Skip to content

Instantly share code, notes, and snippets.

@tomcurran
Created May 6, 2022 12:26
Show Gist options
  • Select an option

  • Save tomcurran/ecf8bb913aa19f0222c014cb39487a3a to your computer and use it in GitHub Desktop.

Select an option

Save tomcurran/ecf8bb913aa19f0222c014cb39487a3a to your computer and use it in GitHub Desktop.
Remove releases from Firebase Distribution using API
using System.Net.Http.Headers;
using System.Net.Http.Json;
namespace FirebaseDistributionReleaseRemove
{
class Program
{
static async Task Main(string[] args)
{
// get project & app for each project from firebase console
// create API key in google cloud console which is the key parameter on API requests
// create service account in google cloud console
// create access token for requests with: oauth2l fetch --scope "https://www.googleapis.com/auth/cloud-platform" --credentials service-account.json
// https://firebase.blog/posts/2021/11/app-distribution-rest-api
var firebaseProject = new FirebaseProject(
projectNumber: "",
androidAppId: "",
iosAppId: "",
accessToken: "",
apiKey: ""
);
await firebaseProject.DeleteReleases();
}
}
class FirebaseProject {
private readonly string _projectNumber;
private readonly string _androidAppId;
private readonly string _iosAppId;
private readonly string _apiKey;
private readonly HttpClient _httpClient;
public FirebaseProject(string projectNumber, string androidAppId, string iosAppId, string accessToken, string apiKey)
{
_projectNumber = projectNumber;
_androidAppId = androidAppId;
_iosAppId = iosAppId;
_apiKey = apiKey;
_httpClient = new HttpClient()
{
BaseAddress = new Uri("https://firebaseappdistribution.googleapis.com")
};
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
}
public async Task DeleteReleases()
{
await DeleteReleases(_androidAppId);
await DeleteReleases(_iosAppId);
}
private async Task DeleteReleases(string appId)
{
var releaseNames = await GetReleaseNames(appId);
var maxBatchDelete = 100;
for (int i = 0; i < releaseNames.Count(); i += maxBatchDelete)
{
await _httpClient.PostAsJsonAsync<ReleasesBatchDeleteRequest>(
$"/v1/projects/{_projectNumber}/apps/{appId}/releases:batchDelete?key={_apiKey}",
new ReleasesBatchDeleteRequest
{
names = releaseNames.Skip(i).Take(maxBatchDelete).ToList(),
}
);
}
}
private async Task<List<string>> GetReleaseNames(string appId)
{
var releaseNames = new List<string>();
ReleasesListResponse? releasesListResponse = null;
do {
releasesListResponse = await _httpClient.GetFromJsonAsync<ReleasesListResponse>(
$"/v1/projects/{_projectNumber}/apps/{appId}/releases?key={_apiKey}&pageSize=100&pageToken={releasesListResponse?.NextPageToken}");
var releaseNamesPage = releasesListResponse?.Releases?.Select(x => x.Name);
if (releaseNamesPage != null) {
releaseNames.AddRange(releaseNamesPage);
}
} while (!string.IsNullOrEmpty(releasesListResponse?.NextPageToken));
return releaseNames;
}
}
// https://firebase.google.com/docs/reference/app-distribution/rest/v1/projects.apps.releases/batchDelete
public class ReleasesBatchDeleteRequest
{
public List<string> names { get; set; }
}
// https://firebase.google.com/docs/reference/app-distribution/rest/v1/projects.apps.releases/list
public class ReleasesListResponse
{
public List<ReleaseModel>? Releases { get; set; }
public string? NextPageToken { get; set; }
}
public class ReleaseModel
{
public string Name { get; set; }
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>FirebaseDistributionReleaseRemove</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment