mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
Merged PR 63702: Add Sonar Client to update permissions and tags in Sonar Projects to new team structure
Add Sonar Client to update permissions and tags in Sonar Projects to new team structure Related work items: #125680
This commit is contained in:
@@ -2,20 +2,20 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.Identity" Version="1.6.0" />
|
||||
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.3.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="5.2.9" />
|
||||
<PackageReference Include="Spectre.Console" Version="0.44.0" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.17.0" />
|
||||
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.8.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.78.0" />
|
||||
<PackageReference Include="Spectre.Console" Version="0.53.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace AzureRestApi.Models.Api
|
||||
namespace AzureRestApi.Models.Api;
|
||||
|
||||
public class ApiResponse<T>
|
||||
{
|
||||
public class ApiResponse<T>
|
||||
{
|
||||
public List<T>? value { get; set; }
|
||||
}
|
||||
}
|
||||
public List<T>? value { get; set; }
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using AzureRestApi.Models.Resources;
|
||||
|
||||
namespace AzureRestApi.Models.Api
|
||||
namespace AzureRestApi.Models.Api;
|
||||
|
||||
public class TagProperties
|
||||
{
|
||||
public class TagProperties
|
||||
{
|
||||
public TagTags properties { get; set; } = new TagTags();
|
||||
}
|
||||
}
|
||||
public TagTags properties { get; set; } = new TagTags();
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace AzureRestApi.Models.Resources
|
||||
namespace AzureRestApi.Models.Resources;
|
||||
|
||||
public class Deployment
|
||||
{
|
||||
public class Deployment
|
||||
{
|
||||
public string? id { get; set; }
|
||||
public string? name { get; set; }
|
||||
public string? type { get; set; }
|
||||
public string? location { get; set; }
|
||||
public DeploymentProperties? properties { get; set; }
|
||||
}
|
||||
}
|
||||
public string? id { get; set; }
|
||||
public string? name { get; set; }
|
||||
public string? type { get; set; }
|
||||
public string? location { get; set; }
|
||||
public DeploymentProperties? properties { get; set; }
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
namespace AzureRestApi.Models.Resources
|
||||
namespace AzureRestApi.Models.Resources;
|
||||
|
||||
public class DeploymentProperties
|
||||
{
|
||||
public class DeploymentProperties
|
||||
{
|
||||
public string? templateHash { get; set; }
|
||||
public string? mode { get; set; }
|
||||
//public string? parameters { get; set; }
|
||||
public string? provisioningState { get; set; }
|
||||
public DateTimeOffset? timestamp { get; set; }
|
||||
public string? duration { get; set; }
|
||||
public string? correlationId { get; set; }
|
||||
// public string? providers { get; set; }
|
||||
//public string? dependencies { get; set; }
|
||||
//public string? outputs { get; set; }
|
||||
public List<Resource>? outputResources { get; set; }
|
||||
}
|
||||
}
|
||||
public string? templateHash { get; set; }
|
||||
public string? mode { get; set; }
|
||||
//public string? parameters { get; set; }
|
||||
public string? provisioningState { get; set; }
|
||||
public DateTimeOffset? timestamp { get; set; }
|
||||
public string? duration { get; set; }
|
||||
public string? correlationId { get; set; }
|
||||
// public string? providers { get; set; }
|
||||
//public string? dependencies { get; set; }
|
||||
//public string? outputs { get; set; }
|
||||
public List<Resource>? outputResources { get; set; }
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
namespace AzureRestApi.Models.Resources
|
||||
{
|
||||
public class Resource
|
||||
{
|
||||
public string? id { get; set; }
|
||||
public string? name { get; set; }
|
||||
public string? type { get; set; }
|
||||
public string? location { get; set; }
|
||||
public string? createdTime { get; set; }
|
||||
public string? changedTime { get; set; }
|
||||
public Dictionary<string, string> tags { get; set; } = new Dictionary<string, string>();
|
||||
namespace AzureRestApi.Models.Resources;
|
||||
|
||||
public string? CreatedOn
|
||||
public class Resource
|
||||
{
|
||||
public string? id { get; set; }
|
||||
public string? name { get; set; }
|
||||
public string? type { get; set; }
|
||||
public string? location { get; set; }
|
||||
public string? createdTime { get; set; }
|
||||
public string? changedTime { get; set; }
|
||||
public Dictionary<string, string> tags { get; set; } = new Dictionary<string, string>();
|
||||
|
||||
public string? CreatedOn
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
if (string.IsNullOrWhiteSpace(createdTime))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(createdTime))
|
||||
{
|
||||
return changedTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
return createdTime;
|
||||
}
|
||||
return changedTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
return createdTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
namespace AzureRestApi.Models.Resources
|
||||
namespace AzureRestApi.Models.Resources;
|
||||
|
||||
public class ResourceGroup
|
||||
{
|
||||
public class ResourceGroup
|
||||
{
|
||||
public string? id { get; set; }
|
||||
public string? name { get; set; }
|
||||
public string? managedBy { get; set; }
|
||||
public string? location { get; set; }
|
||||
public Dictionary<string, string> tags { get; set; } = new Dictionary<string, string>();
|
||||
public DeploymentProperties? properties { get; set; }
|
||||
}
|
||||
}
|
||||
public string? id { get; set; }
|
||||
public string? name { get; set; }
|
||||
public string? managedBy { get; set; }
|
||||
public string? location { get; set; }
|
||||
public Dictionary<string, string> tags { get; set; } = new Dictionary<string, string>();
|
||||
public DeploymentProperties? properties { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace AzureRestApi.Models.Resources
|
||||
namespace AzureRestApi.Models.Resources;
|
||||
|
||||
public class ResourceGroupProperties
|
||||
{
|
||||
public class ResourceGroupProperties
|
||||
{
|
||||
public string? provisioningState { get; set; }
|
||||
}
|
||||
}
|
||||
public string? provisioningState { get; set; }
|
||||
}
|
||||
@@ -1,20 +1,19 @@
|
||||
namespace AzureRestApi.Models.Resources
|
||||
{
|
||||
public class Subscription
|
||||
{
|
||||
public string? id { get; set; }
|
||||
public string? authorizationSource { get; set; }
|
||||
public string? subscriptionId { get; set; }
|
||||
public string? tenantId { get; set; }
|
||||
public string? displayName { get; set; }
|
||||
public string? state { get; set; }
|
||||
namespace AzureRestApi.Models.Resources;
|
||||
|
||||
public bool Enabled
|
||||
public class Subscription
|
||||
{
|
||||
public string? id { get; set; }
|
||||
public string? authorizationSource { get; set; }
|
||||
public string? subscriptionId { get; set; }
|
||||
public string? tenantId { get; set; }
|
||||
public string? displayName { get; set; }
|
||||
public string? state { get; set; }
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return state == "Enabled";
|
||||
}
|
||||
return state == "Enabled";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace AzureRestApi.Models.Resources
|
||||
namespace AzureRestApi.Models.Resources;
|
||||
|
||||
public class TagTags
|
||||
{
|
||||
public class TagTags
|
||||
{
|
||||
public Dictionary<string, string> tags { get; set; } = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
public Dictionary<string, string> tags { get; set; } = new Dictionary<string, string>();
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace AzureRestApi.Models
|
||||
namespace AzureRestApi.Models;
|
||||
|
||||
public class Settings
|
||||
{
|
||||
public class Settings
|
||||
{
|
||||
public string KeyVaultName { get; set; } = string.Empty;
|
||||
public string AzureTenantId { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
public string KeyVaultName { get; set; } = string.Empty;
|
||||
public string AzureTenantId { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -5,37 +5,36 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace AzureRestApi
|
||||
namespace AzureRestApi;
|
||||
|
||||
class Program
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static Task Main(string[] args) =>
|
||||
CreateHostBuilder(args).Build().RunAsync();
|
||||
static Task Main(string[] args) =>
|
||||
CreateHostBuilder(args).Build().RunAsync();
|
||||
|
||||
static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureServices((builder, services) =>
|
||||
{
|
||||
IConfiguration config = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureServices((_, services) =>
|
||||
{
|
||||
IConfiguration config = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();
|
||||
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();
|
||||
|
||||
services.AddSingleton<AccessTokenRepository>();
|
||||
services.AddSingleton(settings);
|
||||
services.AddSingleton<AccessTokenRepository>();
|
||||
services.AddSingleton(settings);
|
||||
|
||||
services.AddHttpClient<AzureSubscriptionRepository>();
|
||||
services.AddHttpClient<AzureDeploymentRepository>();
|
||||
services.AddHttpClient<AzureResourceRepository>();
|
||||
services.AddHttpClient<AzureTagRepository>();
|
||||
services.AddHttpClient<AzureResourceGroupRepository>();
|
||||
services.AddHttpClient<AzureSubscriptionRepository>();
|
||||
services.AddHttpClient<AzureDeploymentRepository>();
|
||||
services.AddHttpClient<AzureResourceRepository>();
|
||||
services.AddHttpClient<AzureTagRepository>();
|
||||
services.AddHttpClient<AzureResourceGroupRepository>();
|
||||
|
||||
services.AddScoped<CreatedOnDateService>();
|
||||
services.AddScoped<DeploymentTypeService>();
|
||||
services.AddScoped<CreatedOnDateService>();
|
||||
services.AddScoped<DeploymentTypeService>();
|
||||
|
||||
services.AddHostedService<OptionService>();
|
||||
} );
|
||||
}
|
||||
services.AddHostedService<OptionService>();
|
||||
});
|
||||
}
|
||||
@@ -1,40 +1,40 @@
|
||||
using Azure.Identity;
|
||||
using Azure.Security.KeyVault.Secrets;
|
||||
using AzureRestApi.Models;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using Microsoft.Identity.Client;
|
||||
|
||||
namespace AzureRestApi.Repositories
|
||||
namespace AzureRestApi.Repositories;
|
||||
|
||||
public class AccessTokenRepository(Settings settings)
|
||||
{
|
||||
public class AccessTokenRepository
|
||||
private string? _accessToken;
|
||||
|
||||
public async Task<string> GetAccessToken()
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
private string? _accessToken;
|
||||
if (!string.IsNullOrWhiteSpace(_accessToken)) return _accessToken;
|
||||
|
||||
public AccessTokenRepository(Settings settings)
|
||||
var keyVaultUri = "https://" + settings.KeyVaultName + ".vault.azure.net";
|
||||
var credential = new DefaultAzureCredential();
|
||||
var client = new SecretClient(new Uri(keyVaultUri), credential);
|
||||
var clientId = (await client.GetSecretAsync("ClientID")).Value.Value;
|
||||
var clientSecret = (await client.GetSecretAsync("ClientSecret")).Value.Value;
|
||||
|
||||
var app = ConfidentialClientApplicationBuilder
|
||||
.Create(clientId)
|
||||
.WithClientSecret(clientSecret)
|
||||
.WithAuthority(new Uri($"https://login.microsoftonline.com/{settings.AzureTenantId}"))
|
||||
.Build();
|
||||
|
||||
var scopes = new[] {"https://management.azure.com/.default"};
|
||||
|
||||
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
|
||||
if (result == null)
|
||||
{
|
||||
_settings = settings;
|
||||
throw new InvalidOperationException("Failed to obtain the Access token");
|
||||
}
|
||||
|
||||
public async Task<string> GetAccessToken()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_accessToken)) return _accessToken;
|
||||
_accessToken = result.AccessToken;
|
||||
|
||||
var keyvaultUri = "https://" + _settings.KeyVaultName + ".vault.azure.net";
|
||||
var credential = new DefaultAzureCredential();
|
||||
var client = new SecretClient(new Uri(keyvaultUri), credential);
|
||||
var clientId = (await client.GetSecretAsync("ClientID")).Value.Value;
|
||||
var clientSecret = (await client.GetSecretAsync("ClientSecret")).Value.Value;
|
||||
|
||||
ClientCredential cc = new(clientId, clientSecret);
|
||||
var context = new AuthenticationContext("https://login.microsoftonline.com/" + _settings.AzureTenantId);
|
||||
var result = context.AcquireTokenAsync("https://management.azure.com/", cc);
|
||||
if (result == null)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to obtain the Access token");
|
||||
}
|
||||
_accessToken = result.Result.AccessToken;
|
||||
|
||||
return _accessToken;
|
||||
}
|
||||
return _accessToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,43 +2,33 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace AzureRestApi.Repositories
|
||||
namespace AzureRestApi.Repositories;
|
||||
|
||||
public abstract class AzureBaseRepository<T>(HttpClient httpClient, AccessTokenRepository accessTokenRepository)
|
||||
{
|
||||
public abstract class AzureBaseRepository<T>
|
||||
protected async Task<List<T>> GetAllByUri(Uri uri)
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
var accessToken = await accessTokenRepository.GetAccessToken();
|
||||
|
||||
public AzureBaseRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository)
|
||||
HttpRequestMessage request = new(HttpMethod.Get, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
|
||||
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var result = JsonSerializer.Deserialize<ApiResponse<T>>(responseString)?.value;
|
||||
return result ?? [];
|
||||
|
||||
}
|
||||
|
||||
protected async Task<List<T>> GetAllByUri(Uri uri)
|
||||
catch
|
||||
{
|
||||
var accessToken = await _accessTokenRepository.GetAccessToken();
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Get, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
|
||||
var response = await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var result = JsonSerializer.Deserialize<ApiResponse<T>>(responseString)?.value;
|
||||
return result ?? new List<T>();
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new List<T>();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,20 @@
|
||||
using AzureRestApi.Models.Resources;
|
||||
|
||||
namespace AzureRestApi.Repositories
|
||||
{
|
||||
public class AzureDeploymentRepository : AzureBaseRepository<Deployment>
|
||||
{
|
||||
public AzureDeploymentRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository) : base(httpClient, accessTokenRepository)
|
||||
{
|
||||
}
|
||||
namespace AzureRestApi.Repositories;
|
||||
|
||||
public async Task<List<Deployment>> GetAllBySubscription(string subscriptionId)
|
||||
{
|
||||
// GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Resources/deployments/?api-version=2021-04-01
|
||||
var uri = new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Resources/deployments/?api-version=2021-04-01");
|
||||
return await GetAllByUri(uri);
|
||||
}
|
||||
public async Task<List<Deployment>> GetAllByResourceGroup(string subscriptionId, string resourceGroupName)
|
||||
{
|
||||
// GET https://management.azure.com/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/?api-version=2021-04-01
|
||||
var uri = new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/?api-version=2021-04-01");
|
||||
return await GetAllByUri(uri);
|
||||
}
|
||||
|
||||
public class AzureDeploymentRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository)
|
||||
: AzureBaseRepository<Deployment>(httpClient, accessTokenRepository)
|
||||
{
|
||||
public async Task<List<Deployment>> GetAllBySubscription(string subscriptionId)
|
||||
{
|
||||
// GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Resources/deployments/?api-version=2021-04-01
|
||||
var uri = new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Resources/deployments/?api-version=2021-04-01");
|
||||
return await GetAllByUri(uri);
|
||||
}
|
||||
}
|
||||
public async Task<List<Deployment>> GetAllByResourceGroup(string subscriptionId, string resourceGroupName)
|
||||
{
|
||||
// GET https://management.azure.com/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/?api-version=2021-04-01
|
||||
var uri = new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/?api-version=2021-04-01");
|
||||
return await GetAllByUri(uri);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,14 @@
|
||||
using AzureRestApi.Models.Resources;
|
||||
|
||||
namespace AzureRestApi.Repositories
|
||||
{
|
||||
public class AzureResourceGroupRepository : AzureBaseRepository<ResourceGroup>
|
||||
{
|
||||
public AzureResourceGroupRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository) : base(httpClient, accessTokenRepository)
|
||||
{
|
||||
}
|
||||
namespace AzureRestApi.Repositories;
|
||||
|
||||
public async Task<List<ResourceGroup>> GetAll(string subscriptionId)
|
||||
{
|
||||
// GET https://management.azure.com/subscriptions/{subscriptionId}/resourcegroups?api-version=2021-04-01
|
||||
var uri = new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/resourcegroups?api-version=2021-04-01");
|
||||
return await GetAllByUri(uri);
|
||||
}
|
||||
public class AzureResourceGroupRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository)
|
||||
: AzureBaseRepository<ResourceGroup>(httpClient, accessTokenRepository)
|
||||
{
|
||||
public async Task<List<ResourceGroup>> GetAll(string subscriptionId)
|
||||
{
|
||||
// GET https://management.azure.com/subscriptions/{subscriptionId}/resourcegroups?api-version=2021-04-01
|
||||
var uri = new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/resourcegroups?api-version=2021-04-01");
|
||||
return await GetAllByUri(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,14 @@
|
||||
using AzureRestApi.Models.Api;
|
||||
using AzureRestApi.Models.Resources;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using AzureRestApi.Models.Resources;
|
||||
|
||||
namespace AzureRestApi.Repositories
|
||||
namespace AzureRestApi.Repositories;
|
||||
|
||||
public class AzureResourceRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository)
|
||||
: AzureBaseRepository<Resource>(httpClient, accessTokenRepository)
|
||||
{
|
||||
public class AzureResourceRepository : AzureBaseRepository<Resource>
|
||||
public async Task<List<Resource>> GetAll(string subscriptionId)
|
||||
{
|
||||
public AzureResourceRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository) : base(httpClient, accessTokenRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<List<Resource>> GetAll(string subscriptionId)
|
||||
{
|
||||
// GET https://management.azure.com/subscriptions/{subscriptionId}/resources?$filter={$filter}&$expand={$expand}&$top={$top}&api-version=2021-04-01
|
||||
var uri = new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/resources?$expand=createdTime,changedTime&api-version=2021-04-01");
|
||||
return await GetAllByUri(uri);
|
||||
}
|
||||
// GET https://management.azure.com/subscriptions/{subscriptionId}/resources?$filter={$filter}&$expand={$expand}&$top={$top}&api-version=2021-04-01
|
||||
var uri = new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/resources?$expand=createdTime,changedTime&api-version=2021-04-01");
|
||||
return await GetAllByUri(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,37 +3,26 @@ using AzureRestApi.Models.Resources;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace AzureRestApi.Repositories
|
||||
namespace AzureRestApi.Repositories;
|
||||
|
||||
public class AzureSubscriptionRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository)
|
||||
{
|
||||
public class AzureSubscriptionRepository
|
||||
public async Task<List<Subscription>?> GetAll()
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
// GET https://management.azure.com/subscriptions?api-version=2020-01-01
|
||||
var accessToken = await accessTokenRepository.GetAccessToken();
|
||||
var uri = new Uri("https://management.azure.com/subscriptions?api-version=2020-01-01");
|
||||
|
||||
public AzureSubscriptionRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
}
|
||||
HttpRequestMessage request = new(HttpMethod.Get, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
|
||||
public async Task<List<Subscription>?> GetAll()
|
||||
{
|
||||
// GET https://management.azure.com/subscriptions?api-version=2020-01-01
|
||||
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var accessToken = await _accessTokenRepository.GetAccessToken();
|
||||
var uri = new Uri("https://management.azure.com/subscriptions?api-version=2020-01-01");
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Get, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
|
||||
var response = await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
return JsonSerializer.Deserialize< ApiResponse<Subscription>>(responseString)?.value;
|
||||
}
|
||||
return JsonSerializer.Deserialize< ApiResponse<Subscription>>(responseString)?.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,50 +4,38 @@ using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace AzureRestApi.Repositories
|
||||
namespace AzureRestApi.Repositories;
|
||||
|
||||
public class AzureTagRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository)
|
||||
{
|
||||
public class AzureTagRepository
|
||||
public async Task<bool> SetTag(string scope, string name, string value)
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly AccessTokenRepository _accessTokenRepository;
|
||||
private readonly ILogger<AzureTagRepository> _logger;
|
||||
// PUT https://management.azure.com/{scope}/providers/Microsoft.Resources/tags/default?api-version=2021-04-01
|
||||
var result = true;
|
||||
var accessToken = await accessTokenRepository.GetAccessToken();
|
||||
var uri = new Uri("https://management.azure.com/" + scope + "/providers/Microsoft.Resources/tags/default?api-version=2021-04-01");
|
||||
|
||||
public AzureTagRepository(HttpClient httpClient, AccessTokenRepository accessTokenRepository, ILogger<AzureTagRepository> logger)
|
||||
var tagProperties = new TagProperties();
|
||||
tagProperties.properties.tags.Add(name, value);
|
||||
var body = JsonSerializer.Serialize(tagProperties);
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Put, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
|
||||
|
||||
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_accessTokenRepository = accessTokenRepository;
|
||||
_logger = logger;
|
||||
response.EnsureSuccessStatusCode();
|
||||
await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
public async Task<bool> SetTag(string scope, string name, string value)
|
||||
{
|
||||
// PUT https://management.azure.com/{scope}/providers/Microsoft.Resources/tags/default?api-version=2021-04-01
|
||||
var result = true;
|
||||
var accessToken = await _accessTokenRepository.GetAccessToken();
|
||||
var uri = new Uri("https://management.azure.com/" + scope + "/providers/Microsoft.Resources/tags/default?api-version=2021-04-01");
|
||||
|
||||
var tagProperties = new TagProperties();
|
||||
tagProperties.properties.tags.Add(name, value);
|
||||
var body = JsonSerializer.Serialize(tagProperties);
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Put, uri);
|
||||
request.Headers.Accept.Clear();
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
|
||||
|
||||
var response = await _httpClient.SendAsync(request).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,61 @@
|
||||
using AzureRestApi.Repositories;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace AzureRestApi.Services
|
||||
namespace AzureRestApi.Services;
|
||||
|
||||
public class CreatedOnDateService(
|
||||
AzureSubscriptionRepository azureSubscriptionRepository,
|
||||
AzureResourceRepository azureResourceRepository,
|
||||
AzureTagRepository azureTagRepository)
|
||||
{
|
||||
public class CreatedOnDateService
|
||||
private const string TagName = "CreatedOnDate";
|
||||
|
||||
public async Task SetCreatedOnDateTags(bool skipDone = true)
|
||||
{
|
||||
private const string TagName = "CreatedOnDate";
|
||||
private readonly AzureSubscriptionRepository _azureSubscriptionRepository;
|
||||
private readonly AzureResourceRepository _azureResourceRepository;
|
||||
private readonly AzureTagRepository _azureTagRepository;
|
||||
|
||||
public CreatedOnDateService(AzureSubscriptionRepository azureSubscriptionRepository, AzureResourceRepository azureResourceRepository, AzureTagRepository azureTagRepository)
|
||||
var rule = new Rule("[skyblue1]Setting CreatedOnDateTags[/]")
|
||||
{
|
||||
_azureSubscriptionRepository = azureSubscriptionRepository;
|
||||
_azureResourceRepository = azureResourceRepository;
|
||||
_azureTagRepository = azureTagRepository;
|
||||
}
|
||||
Justification = Justify.Left,
|
||||
Style = Style.Parse("skyblue1")
|
||||
};
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
public async Task SetCreatedOnDateTags(bool skipDone = true)
|
||||
{
|
||||
var rule = new Rule("[skyblue1]Setting CreatedOnDateTags[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1");
|
||||
AnsiConsole.Write(rule);
|
||||
await AnsiConsole.Status()
|
||||
.AutoRefresh(true)
|
||||
.Spinner(Spinner.Known.Default)
|
||||
.StartAsync("Retrieving subscriptions...", async ctx =>
|
||||
{
|
||||
var subscriptions = await azureSubscriptionRepository.GetAll();
|
||||
if (subscriptions == null || subscriptions.Count == 0) throw new Exception("No subscriptions found");
|
||||
subscriptions = subscriptions.Where(s => s.Enabled && !string.IsNullOrWhiteSpace(s.subscriptionId)).ToList();
|
||||
if (subscriptions.Count == 0) throw new Exception("No subscriptions found");
|
||||
|
||||
await AnsiConsole.Status()
|
||||
.AutoRefresh(true)
|
||||
.Spinner(Spinner.Known.Default)
|
||||
.StartAsync("Retrieving subscriptions...", async ctx =>
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
var subscriptions = await _azureSubscriptionRepository.GetAll();
|
||||
if (subscriptions == null || !subscriptions.Any()) throw new Exception("No subscriptions found");
|
||||
subscriptions = subscriptions.Where(s => s.Enabled && !string.IsNullOrWhiteSpace(s.subscriptionId)).ToList();
|
||||
if (!subscriptions.Any()) throw new Exception("No subscriptions found");
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
rule = new Rule($"[skyblue1]{subscription.displayName}[/]")
|
||||
{
|
||||
rule = new Rule($"[skyblue1]{subscription.displayName}[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1 dim");
|
||||
AnsiConsole.Write(rule);
|
||||
Justification = Justify.Left,
|
||||
Style = Style.Parse("skyblue1 dim")
|
||||
};
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
ctx.Status($"Getting the resources for subscription '{subscription.displayName}'");
|
||||
ctx.Status($"Getting the resources for subscription '{subscription.displayName}'");
|
||||
|
||||
var resources = await _azureResourceRepository.GetAll(subscription.subscriptionId);
|
||||
if (resources == null || !resources.Any()) continue;
|
||||
resources = resources.Where(r => !string.IsNullOrWhiteSpace(r.CreatedOn) && !string.IsNullOrWhiteSpace(r.id)).ToList();
|
||||
var resources = await azureResourceRepository.GetAll(subscription.subscriptionId);
|
||||
if (resources == null || resources.Count == 0) continue;
|
||||
resources = resources.Where(r => !string.IsNullOrWhiteSpace(r.CreatedOn) && !string.IsNullOrWhiteSpace(r.id)).ToList();
|
||||
|
||||
if (skipDone)
|
||||
{
|
||||
resources = resources.Where(r => !r.tags.Any(t => t.Key == TagName && !string.IsNullOrWhiteSpace(t.Value))).ToList();
|
||||
}
|
||||
|
||||
ctx.Status($"Setting created date tag on resources in subscription '{subscription.displayName}'");
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
var tagSuccess = await _azureTagRepository.SetTag(resource.id, TagName, resource.CreatedOn);
|
||||
AnsiConsole.MarkupLine($"{resource.id} " + (tagSuccess ? "[green]V[/]" : "[red]X[/]"));
|
||||
}
|
||||
if (skipDone)
|
||||
{
|
||||
resources = resources.Where(r => !r.tags.Any(t => t.Key == TagName && !string.IsNullOrWhiteSpace(t.Value))).ToList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ctx.Status($"Setting created date tag on resources in subscription '{subscription.displayName}'");
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
var tagSuccess = await azureTagRepository.SetTag(resource.id, TagName, resource.CreatedOn);
|
||||
AnsiConsole.MarkupLine($"{resource.id} " + (tagSuccess ? "[green]V[/]" : "[red]X[/]"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +1,65 @@
|
||||
using AzureRestApi.Repositories;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace AzureRestApi.Services
|
||||
namespace AzureRestApi.Services;
|
||||
|
||||
public class DeploymentTypeService(
|
||||
AzureSubscriptionRepository azureSubscriptionRepository,
|
||||
AzureDeploymentRepository azureDeploymentRepository,
|
||||
AzureResourceGroupRepository azureResourceGroupRepository)
|
||||
{
|
||||
public class DeploymentTypeService
|
||||
public async Task CheckDeploymentTypes()
|
||||
{
|
||||
private readonly AzureSubscriptionRepository _azureSubscriptionRepository;
|
||||
private readonly AzureDeploymentRepository _azureDeploymentRepository;
|
||||
private readonly AzureResourceGroupRepository _azureResourceGroupRepository;
|
||||
|
||||
public DeploymentTypeService(AzureSubscriptionRepository azureSubscriptionRepository, AzureDeploymentRepository azureDeploymentRepository, AzureResourceGroupRepository azureResourceGroupRepository)
|
||||
var rule = new Rule("[skyblue1]Checking deployment types[/]")
|
||||
{
|
||||
_azureSubscriptionRepository = azureSubscriptionRepository;
|
||||
_azureDeploymentRepository = azureDeploymentRepository;
|
||||
_azureResourceGroupRepository = azureResourceGroupRepository;
|
||||
}
|
||||
Justification = Justify.Left,
|
||||
Style = Style.Parse("skyblue1")
|
||||
};
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
public async Task CheckDeploymentTypes()
|
||||
{
|
||||
var rule = new Rule("[skyblue1]Checking deployment types[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1");
|
||||
AnsiConsole.Write(rule);
|
||||
await AnsiConsole.Status()
|
||||
.AutoRefresh(true)
|
||||
.Spinner(Spinner.Known.Default)
|
||||
.StartAsync("Retrieving subscriptions...", async ctx =>
|
||||
{
|
||||
// Retrieve subscriptions
|
||||
var subscriptions = await azureSubscriptionRepository.GetAll();
|
||||
if (subscriptions == null || !subscriptions.Any()) throw new Exception("No subscriptions found");
|
||||
subscriptions = subscriptions.Where(s => s.Enabled && !string.IsNullOrWhiteSpace(s.subscriptionId)).ToList();
|
||||
if (subscriptions.Count == 0) throw new Exception("No subscriptions found");
|
||||
|
||||
await AnsiConsole.Status()
|
||||
.AutoRefresh(true)
|
||||
.Spinner(Spinner.Known.Default)
|
||||
.StartAsync("Retrieving subscriptions...", async ctx =>
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
// Retrieve subscriptions
|
||||
var subscriptions = await _azureSubscriptionRepository.GetAll();
|
||||
if (subscriptions == null || !subscriptions.Any()) throw new Exception("No subscriptions found");
|
||||
subscriptions = subscriptions.Where(s => s.Enabled && !string.IsNullOrWhiteSpace(s.subscriptionId)).ToList();
|
||||
if (!subscriptions.Any()) throw new Exception("No subscriptions found");
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
rule = new Rule($"[skyblue1]{subscription.displayName}[/]")
|
||||
{
|
||||
rule = new Rule($"[skyblue1]{subscription.displayName}[/]");
|
||||
rule.Alignment = Justify.Left;
|
||||
rule.Style = Style.Parse("skyblue1 dim");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
ctx.Status($"Getting the deployments for subscription '{subscription.displayName}'");
|
||||
var deployments = await _azureDeploymentRepository.GetAllBySubscription(subscription.subscriptionId);
|
||||
|
||||
if (deployments == null || !deployments.Any()) continue;
|
||||
|
||||
foreach (var deployment in deployments)
|
||||
{
|
||||
AnsiConsole.WriteLine(Markup.Escape(deployment?.name));
|
||||
}
|
||||
|
||||
ctx.Status($"Getting the resource groups for subscription '{subscription.displayName}'");
|
||||
var resourceGroups = await _azureResourceGroupRepository.GetAll(subscription.subscriptionId);
|
||||
foreach (var resourceGroup in resourceGroups)
|
||||
{
|
||||
ctx.Status($"Getting the deployments for resourcegroup {resourceGroup.name} in subscription '{subscription.displayName}'");
|
||||
|
||||
var resourceGroupDeployments = await _azureDeploymentRepository.GetAllByResourceGroup(subscription.subscriptionId, resourceGroup.name);
|
||||
foreach (var deployment in resourceGroupDeployments)
|
||||
{
|
||||
AnsiConsole.WriteLine(Markup.Escape($"{resourceGroup.name} - {deployment?.name}"));
|
||||
}
|
||||
}
|
||||
Justification = Justify.Left,
|
||||
Style = Style.Parse("skyblue1 dim")
|
||||
};
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
ctx.Status($"Getting the deployments for subscription '{subscription.displayName}'");
|
||||
var deployments = await azureDeploymentRepository.GetAllBySubscription(subscription.subscriptionId);
|
||||
|
||||
if (deployments == null || deployments.Count == 0) continue;
|
||||
|
||||
foreach (var deployment in deployments)
|
||||
{
|
||||
AnsiConsole.WriteLine(Markup.Escape(deployment?.name));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ctx.Status($"Getting the resource groups for subscription '{subscription.displayName}'");
|
||||
var resourceGroups = await azureResourceGroupRepository.GetAll(subscription.subscriptionId);
|
||||
foreach (var resourceGroup in resourceGroups)
|
||||
{
|
||||
ctx.Status($"Getting the deployments for resourcegroup {resourceGroup.name} in subscription '{subscription.displayName}'");
|
||||
|
||||
var resourceGroupDeployments = await azureDeploymentRepository.GetAllByResourceGroup(subscription.subscriptionId, resourceGroup.name);
|
||||
foreach (var deployment in resourceGroupDeployments)
|
||||
{
|
||||
AnsiConsole.WriteLine(Markup.Escape($"{resourceGroup.name} - {deployment?.name}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +1,47 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Spectre.Console;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AzureRestApi.Services
|
||||
namespace AzureRestApi.Services;
|
||||
|
||||
public class OptionService(CreatedOnDateService createdOnDateService, DeploymentTypeService deploymentTypeService)
|
||||
: IHostedService
|
||||
{
|
||||
public class OptionService : IHostedService
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
private readonly ILogger<OptionService> _logger;
|
||||
private readonly CreatedOnDateService _createdOnDateService;
|
||||
private readonly DeploymentTypeService _deploymentTypeService;
|
||||
var rule = new Rule("[yellow]Cloud Egineering Console App[/]");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
public OptionService(ILogger<OptionService> logger, CreatedOnDateService createdOnDateService, DeploymentTypeService deploymentTypeService)
|
||||
Console.WriteLine("-- This couldn't be done with Powershell, so here we are.... ");
|
||||
Console.WriteLine();
|
||||
|
||||
var choices = new[]
|
||||
{
|
||||
_logger = logger;
|
||||
_createdOnDateService = createdOnDateService;
|
||||
_deploymentTypeService = deploymentTypeService;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var rule = new Rule("[yellow]Cloud Egineering Console App[/]");
|
||||
AnsiConsole.Write(rule);
|
||||
|
||||
Console.WriteLine("-- This couldn't be done with Powershell, so here we are.... ");
|
||||
Console.WriteLine();
|
||||
|
||||
var choices = new[]
|
||||
{
|
||||
"Update missing CreatedOnDate tags.",
|
||||
"Update missing IaC Deployment type tags.",
|
||||
"Exit"
|
||||
};
|
||||
var result = AnsiConsole.Prompt(new SelectionPrompt<string>()
|
||||
.Title("Select what you want to do:")
|
||||
.PageSize(10)
|
||||
.MoreChoicesText("[grey](Move up and down to reveal more choices)[/]")
|
||||
.AddChoices(choices));
|
||||
|
||||
if (result == choices[0])
|
||||
{
|
||||
await _createdOnDateService.SetCreatedOnDateTags(true);
|
||||
}
|
||||
else if (result == choices[1])
|
||||
{
|
||||
await _deploymentTypeService.CheckDeploymentTypes();
|
||||
}
|
||||
|
||||
rule = new Rule("[yellow]Done. Bye.[/]");
|
||||
AnsiConsole.Write(rule);
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
"Update missing CreatedOnDate tags.",
|
||||
"Update missing IaC Deployment type tags.",
|
||||
"Exit"
|
||||
};
|
||||
var result = AnsiConsole.Prompt(new SelectionPrompt<string>()
|
||||
.Title("Select what you want to do:")
|
||||
.PageSize(10)
|
||||
.MoreChoicesText("[grey](Move up and down to reveal more choices)[/]")
|
||||
.AddChoices(choices));
|
||||
|
||||
if (result == choices[0])
|
||||
{
|
||||
await createdOnDateService.SetCreatedOnDateTags(true);
|
||||
}
|
||||
else if (result == choices[1])
|
||||
{
|
||||
await deploymentTypeService.CheckDeploymentTypes();
|
||||
}
|
||||
|
||||
rule = new Rule("[yellow]Done. Bye.[/]");
|
||||
AnsiConsole.Write(rule);
|
||||
}
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ConsoleApp1
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user