Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Découvrez comment créer une application .NET qui peut être utilisée en tant qu’action GitHub. GitHub Actions permet l’automatisation et la composition des flux de travail. Avec GitHub Actions, vous pouvez générer, tester et déployer du code source à partir de GitHub. En outre, les actions exposent la possibilité d’interagir par programmation avec des problèmes, de créer des demandes de tirage, d’effectuer des révisions de code et de gérer des branches. Pour plus d’informations sur l’intégration continue à GitHub Actions, consultez Génération et test de .NET.
Dans ce tutoriel, vous allez apprendre à :
- Préparer une application .NET pour GitHub Actions
- Définir les entrées et sorties d’action
- Composer un flux de travail
Prerequisites
- Un compte GitHub
- Kit de développement logiciel (SDK) .NET 6 ou version ultérieure
- Un environnement de développement intégré .NET (IDE)
- N’hésitez pas à utiliser l’IDE Visual Studio
L’intention de l’application
L’application de ce tutoriel effectue l’analyse des métriques de code en procédant comme suit :
Analyse et découverte des fichiers projet *.csproj et *.vbproj .
Analyse du code source découvert dans ces projets pour :
- Complexité cyclomatique
- Index de maintenance
- Profondeur de l’héritage
- Couplage de classe
- Nombre de lignes de code source
- Lignes approximatives de code exécutable
Création (ou mise à jour) d’un fichier CODE_METRICS.md .
L'application n'est pas responsable de la création d'un pull request avec les modifications apportées au fichier CODE_METRICS.md. Ces modifications sont gérées dans le cadre de la composition du flux de travail.
Les références au code source de ce didacticiel ont des parties de l’application omises pour la concision. Le code complet de l’application est disponible sur GitHub.
Explorer l’application
L’application console .NET utilise le CommandLineParser package NuGet pour analyser les arguments dans l’objet ActionInputs .
using CommandLine;
namespace DotNet.GitHubAction;
public class ActionInputs
{
string _repositoryName = null!;
string _branchName = null!;
public ActionInputs()
{
if (Environment.GetEnvironmentVariable("GREETINGS") is { Length: > 0 } greetings)
{
Console.WriteLine(greetings);
}
}
[Option('o', "owner",
Required = true,
HelpText = "The owner, for example: \"dotnet\". Assign from `github.repository_owner`.")]
public string Owner { get; set; } = null!;
[Option('n', "name",
Required = true,
HelpText = "The repository name, for example: \"samples\". Assign from `github.repository`.")]
public string Name
{
get => _repositoryName;
set => ParseAndAssign(value, str => _repositoryName = str);
}
[Option('b', "branch",
Required = true,
HelpText = "The branch name, for example: \"refs/heads/main\". Assign from `github.ref`.")]
public string Branch
{
get => _branchName;
set => ParseAndAssign(value, str => _branchName = str);
}
[Option('d', "dir",
Required = true,
HelpText = "The root directory to start recursive searching from.")]
public string Directory { get; set; } = null!;
[Option('w', "workspace",
Required = true,
HelpText = "The workspace directory, or repository root directory.")]
public string WorkspaceDirectory { get; set; } = null!;
static void ParseAndAssign(string? value, Action<string> assign)
{
if (value is { Length: > 0 } && assign is not null)
{
assign(value.Split("/")[^1]);
}
}
}
La classe d’entrées d’action précédente définit plusieurs entrées requises pour que l’application s’exécute correctement. Le constructeur écrit la valeur de la "GREETINGS" variable d’environnement, si celle-ci est disponible dans l’environnement d’exécution actuel. Les propriétés Name et Branch sont interprétées et affectées à partir du dernier segment d'une chaîne délimitée "/".
Avec la classe d’entrées d’action définie, concentrez-vous sur le fichier Program.cs .
using System.Text;
using CommandLine;
using DotNet.GitHubAction;
using DotNet.GitHubAction.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using static CommandLine.Parser;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddGitHubActionServices();
using IHost host = builder.Build();
ParserResult<ActionInputs> parser = Default.ParseArguments<ActionInputs>(() => new(), args);
parser.WithNotParsed(
errors =>
{
host.Services
.GetRequiredService<ILoggerFactory>()
.CreateLogger("DotNet.GitHubAction.Program")
.LogError("{Errors}", string.Join(
Environment.NewLine, errors.Select(error => error.ToString())));
Environment.Exit(2);
});
await parser.WithParsedAsync(
async options => await StartAnalysisAsync(options, host));
await host.RunAsync();
static async ValueTask StartAnalysisAsync(ActionInputs inputs, IHost host)
{
// Omitted for brevity, here is the pseudo code:
// - Read projects
// - Calculate code metric analytics
// - Write the CODE_METRICS.md file
// - Set the outputs
var updatedMetrics = true;
var title = "Updated 2 projects";
var summary = "Calculated code metrics on two projects.";
// Do the work here...
// Write GitHub Action workflow outputs.
var gitHubOutputFile = Environment.GetEnvironmentVariable("GITHUB_OUTPUT");
if (!string.IsNullOrWhiteSpace(gitHubOutputFile))
{
using StreamWriter textWriter = new(gitHubOutputFile, true, Encoding.UTF8);
textWriter.WriteLine($"updated-metrics={updatedMetrics}");
textWriter.WriteLine($"summary-title={title}");
textWriter.WriteLine($"summary-details={summary}");
}
await ValueTask.CompletedTask;
Environment.Exit(0);
}
Le Program fichier est simplifié pour la concision, pour explorer l’exemple de source complet, consultez Program.cs. Les principes de base en place illustrent le code standard nécessaire à l’utilisation :
Les références de projet ou de package externes peuvent être utilisées et enregistrées avec l’injection de dépendances. La fonction locale statique Get<TService> nécessite l'instance IHost et est utilisée pour résoudre les services nécessaires. Avec le CommandLine.Parser.Default singleton, l’application obtient une instance parser de args. Lorsque les arguments ne peuvent pas être analysés, l’application se termine par un code de sortie différent de zéro. Pour plus d’informations, consultez Définition des codes de sortie pour les actions.
Lorsque les arguments sont correctement analysés, l’application a été appelée correctement avec les entrées requises. Dans ce cas, un appel à la fonctionnalité StartAnalysisAsync principale est effectué.
Pour écrire des valeurs de sortie, vous devez suivre le format reconnu par GitHub Actions : définition d’un paramètre de sortie.
Préparer l’application .NET pour GitHub Actions
GitHub Actions prend en charge deux variantes du développement d’applications, soit
- JavaScript (éventuellement TypeScript)
- Conteneur Docker (toute application qui s’exécute sur Docker)
L’environnement virtuel dans lequel GitHub Action est hébergé peut ou non avoir .NET installé. Pour plus d’informations sur ce qui est préinstallé dans l’environnement cible, consultez Environnements virtuels GitHub Actions. Bien qu'il soit possible d'exécuter des commandes CLI .NET à partir des workflows GitHub Actions, pour une GitHub Action .NET plus fonctionnelle, nous vous recommandons de containeriser l'application. Pour plus d’informations, consultez Conteneuriser une application .NET.
Le fichier Dockerfile
Un fichier Dockerfile est un ensemble d’instructions pour générer une image. Pour les applications .NET, le fichier Dockerfile se trouve généralement à la racine du répertoire en regard d’un fichier de solution.
# Set the base image as the .NET 7.0 SDK (this includes the runtime)
FROM mcr.microsoft.com/dotnet/sdk:7.0@sha256:d32bd65cf5843f413e81f5d917057c82da99737cb1637e905a1a4bc2e7ec6c8d as build-env
# Copy everything and publish the release (publish implicitly restores and builds)
WORKDIR /app
COPY . ./
RUN dotnet publish ./DotNet.GitHubAction/DotNet.GitHubAction.csproj -c Release -o out --no-self-contained
# Label the container
LABEL maintainer="David Pine <david.pine@microsoft.com>"
LABEL repository="https://github.com/dotnet/samples"
LABEL homepage="https://github.com/dotnet/samples"
# Label as GitHub action
LABEL com.github.actions.name="The name of your GitHub Action"
# Limit to 160 characters
LABEL com.github.actions.description="The description of your GitHub Action."
# See branding:
# https://docs.github.com/actions/creating-actions/metadata-syntax-for-github-actions#branding
LABEL com.github.actions.icon="activity"
LABEL com.github.actions.color="orange"
# Relayer the .NET SDK, anew with the build output
FROM mcr.microsoft.com/dotnet/sdk:7.0@sha256:d32bd65cf5843f413e81f5d917057c82da99737cb1637e905a1a4bc2e7ec6c8d
COPY --from=build-env /app/out .
ENTRYPOINT [ "dotnet", "/DotNet.GitHubAction.dll" ]
Note
L’application .NET de ce tutoriel s’appuie sur le Kit de développement logiciel (SDK) .NET dans le cadre de ses fonctionnalités. Le fichier Dockerfile crée un ensemble de couches Docker, indépendamment des couches précédentes. Elle commence à partir de zéro avec l’image du Kit de développement logiciel (SDK) et ajoute le résultat de la compilation des couches précédentes. Pour les applications qui n’ont pas besoin du Kit de développement logiciel (SDK) .NET dans le cadre de leurs fonctionnalités, elles doivent s’appuyer uniquement sur le runtime .NET à la place. Cela réduit considérablement la taille de l’image.
FROM mcr.microsoft.com/dotnet/runtime:7.0
Avertissement
Faites attention à chaque étape du fichier Dockerfile, car elle diffère du fichier Dockerfile standard créé à partir de la fonctionnalité « ajouter la prise en charge de Docker ». En particulier, les dernières étapes varient en ne spécifiant pas de nouveau WORKDIR qui modifierait le chemin d’accès vers l’application ENTRYPOINT.
Les étapes dockerfile précédentes sont les suivantes :
- Définition de l'image de base depuis
mcr.microsoft.com/dotnet/sdk:7.0en tant qu'aliasbuild-env. - Copie du contenu et publication de l’application .NET :
- L’application est publiée à l’aide de la
dotnet publishcommande.
- L’application est publiée à l’aide de la
- Application d’étiquettes au conteneur.
- Relayer l’image du Kit de développement logiciel (SDK) .NET à partir de
mcr.microsoft.com/dotnet/sdk:7.0 - Copie de la sortie de build publiée à partir du
build-env. - Définir le point d’entrée qui délègue à
dotnet /DotNet.GitHubAction.dll.
Conseil / Astuce
Le MCR mcr.microsoft.com signifie « Microsoft Container Registry » et est le catalogue de conteneurs syndiqué de Microsoft à partir du hub Docker officiel. Pour plus d’informations, consultez le catalogue de conteneurs de syndicat Microsoft.
Caution
Si vous utilisez un fichier global.json pour épingler la version du Kit de développement logiciel (SDK), vous devez vous référer explicitement à cette version dans votre fichier Dockerfile. Par exemple, si vous avez utilisé global.json pour épingler la version 5.0.300du Kit de développement logiciel (SDK), votre fichier Dockerfile doit utiliser mcr.microsoft.com/dotnet/sdk:5.0.300. Cela empêche l’interruption des actions GitHub lorsqu’une nouvelle révision mineure est publiée.
Définir les entrées et sorties d’action
Dans la section Explorer l’application , vous avez découvert la ActionInputs classe. Cet objet représente les entrées de l’action GitHub. Pour que GitHub reconnaisse que le dépôt est une action GitHub, vous devez disposer d’un fichier action.yml à la racine du référentiel.
name: 'The title of your GitHub Action'
description: 'The description of your GitHub Action'
branding:
icon: activity
color: orange
inputs:
owner:
description:
'The owner of the repo. Assign from github.repository_owner. Example, "dotnet".'
required: true
name:
description:
'The repository name. Example, "samples".'
required: true
branch:
description:
'The branch name. Assign from github.ref. Example, "refs/heads/main".'
required: true
dir:
description:
'The root directory to work from. Examples, "path/to/code".'
required: false
default: '/github/workspace'
outputs:
summary-title:
description:
'The title of the code metrics action.'
summary-details:
description:
'A detailed summary of all the projects that were flagged.'
updated-metrics:
description:
'A boolean value, indicating whether or not the action updated metrics.'
runs:
using: 'docker'
image: 'Dockerfile'
args:
- '-o'
- ${{ inputs.owner }}
- '-n'
- ${{ inputs.name }}
- '-b'
- ${{ inputs.branch }}
- '-d'
- ${{ inputs.dir }}
Le fichier action.yml précédent définit :
-
nameetdescriptionde l’action GitHub - Le
branding, qui est utilisé dans le GitHub Marketplace pour vous aider à identifier votre action de manière unique - Le
inputs, qui correspond un-à-un avec la classeActionInputs - ,
outputsqui est écrit dans leProgramet utilisé dans le cadre de la composition du flux de travail - Nœud
runs, qui indique à GitHub que l’application est unedockerapplication et quels arguments lui transmettre
Pour plus d’informations, consultez la syntaxe des métadonnées pour GitHub Actions.
Variables d’environnement prédéfinies
Avec GitHub Actions, vous obtiendrez un grand nombre de variables d’environnement par défaut. Par exemple, la variable GITHUB_REF contient toujours une référence à la branche ou à la balise qui a déclenché l’exécution du flux de travail.
GITHUB_REPOSITORY a le nom du propriétaire et du référentiel, par exemple dotnet/docs.
Vous devez explorer les variables d’environnement prédéfinies et les utiliser en conséquence.
Composition du flux de travail
Avec l’application .NET conteneurisée et les entrées et sorties d’action définies, vous êtes prêt à utiliser l’action. GitHub Actions n'ont pas besoin d'être publiés sur le marché GitHub pour être utilisés. Les flux de travail sont définis dans le répertoire .github/workflows d’un référentiel sous forme de fichiers YAML.
# The name of the work flow. Badges will use this name
name: '.NET code metrics'
on:
push:
branches: [ main ]
paths:
- 'github-actions/DotNet.GitHubAction/**' # run on all changes to this dir
- '!github-actions/DotNet.GitHubAction/CODE_METRICS.md' # ignore this file
workflow_dispatch:
inputs:
reason:
description: 'The reason for running the workflow'
required: true
default: 'Manual run'
jobs:
analysis:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v3
- name: 'Print manual run reason'
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
echo 'Reason: ${{ github.event.inputs.reason }}'
- name: .NET code metrics
id: dotnet-code-metrics
uses: dotnet/samples/github-actions/DotNet.GitHubAction@main
env:
GREETINGS: 'Hello, .NET developers!' # ${{ secrets.GITHUB_TOKEN }}
with:
owner: ${{ github.repository_owner }}
name: ${{ github.repository }}
branch: ${{ github.ref }}
dir: ${{ './github-actions/DotNet.GitHubAction' }}
- name: Create pull request
uses: peter-evans/create-pull-request@v4
if: ${{ steps.dotnet-code-metrics.outputs.updated-metrics }} == 'true'
with:
title: '${{ steps.dotnet-code-metrics.outputs.summary-title }}'
body: '${{ steps.dotnet-code-metrics.outputs.summary-details }}'
commit-message: '.NET code metrics, automated pull request.'
Important
Pour les actions GitHub conteneurisées, vous devez utiliser runs-on: ubuntu-latest. Pour plus d’informations, consultez la syntaxe jobs.<job_id>.runs-ondu flux de travail.
Le fichier YAML du flux de travail précédent définit trois nœuds principaux :
- Flux
namede travail. Ce nom est également utilisé lors de la création d’un badge d’état de flux de travail. - Le
onnœud définit quand et comment l’action est déclenchée. - Le
jobsnœud décrit les différents travaux et étapes de chaque travail. Les étapes individuelles consomment GitHub Actions.
Pour plus d’informations, consultez Création de votre premier flux de travail.
En mettant l’accent sur le steps nœud, la composition est plus évidente :
steps:
- uses: actions/checkout@v3
- name: 'Print manual run reason'
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
echo 'Reason: ${{ github.event.inputs.reason }}'
- name: .NET code metrics
id: dotnet-code-metrics
uses: dotnet/samples/github-actions/DotNet.GitHubAction@main
env:
GREETINGS: 'Hello, .NET developers!' # ${{ secrets.GITHUB_TOKEN }}
with:
owner: ${{ github.repository_owner }}
name: ${{ github.repository }}
branch: ${{ github.ref }}
dir: ${{ './github-actions/DotNet.GitHubAction' }}
- name: Create pull request
uses: peter-evans/create-pull-request@v4
if: ${{ steps.dotnet-code-metrics.outputs.updated-metrics }} == 'true'
with:
title: '${{ steps.dotnet-code-metrics.outputs.summary-title }}'
body: '${{ steps.dotnet-code-metrics.outputs.summary-details }}'
commit-message: '.NET code metrics, automated pull request.'
Représente jobs.steps la composition du flux de travail. Les étapes sont orchestrées de façon à ce qu’elles soient séquentielles, communicatives et composables. Avec différentes actions GitHub représentant des étapes, chacune ayant des entrées et des sorties, les flux de travail peuvent être composés.
Dans les étapes précédentes, vous pouvez observer :
Le référentiel est consulté.
Un message est imprimé dans le journal de flux de travail, lorsqu’il est exécuté manuellement.
Une étape identifiée comme
dotnet-code-metrics:-
uses: dotnet/samples/github-actions/DotNet.GitHubAction@mainest l’emplacement de l’application .NET conteneurisée dans ce tutoriel. -
envcrée une variable"GREETING"d’environnement, qui est imprimée dans l’exécution de l’application. -
withspécifie chacune des entrées d’action requises.
-
Une étape conditionnelle, nommée
Create pull request, s’exécute lorsque l’étapedotnet-code-metricsspécifie un paramètre de sortie et dont la valeur deupdated-metricsesttrue.
Important
GitHub permet la création de secrets chiffrés. Les secrets peuvent être utilisés dans la composition du flux de travail à l’aide de la ${{ secrets.SECRET_NAME }} syntaxe. Dans le contexte d’une action GitHub, il existe un jeton GitHub qui est automatiquement rempli par défaut : ${{ secrets.GITHUB_TOKEN }}. Pour plus d’informations, consultez la syntaxe de contexte et d’expression pour GitHub Actions.
Mets tout ensemble
Le dépôt GitHub dotnet/samples abrite de nombreux exemples de projets de code source .NET, y compris l’application dans ce didacticiel.
Le fichier CODE_METRICS.md généré est navigable. Ce fichier représente la hiérarchie des projets qu’il a analysés. Chaque projet a une section de niveau supérieur et un emoji qui représente l’état global de la complexité cyclomatique la plus élevée pour les objets imbriqués. Lorsque vous naviguez dans le fichier, chaque section expose des opportunités d’exploration avec un résumé de chaque zone. Le markdown a des sections repliables comme commodité supplémentaire.
La hiérarchie progresse à partir de :
- Fichier projet à assemblage
- Assembly vers l’espace de noms
- Espace de noms vers type nommé
- Chaque type nommé a une table et chaque table a :
- Liens vers des numéros de ligne pour les champs, méthodes et propriétés
- Évaluations individuelles pour les métriques de code
En action
Le flux de travail spécifie qu’une onpush branche main est activée, l’action est déclenchée pour s’exécuter. Lorsqu’il s’exécute, l’onglet Actions dans GitHub signale le flux de journal en direct de son exécution. Voici un exemple de log de l'exécution .NET code metrics :
Améliorations des performances
Si vous avez suivi l’exemple, vous avez peut-être remarqué que chaque fois que cette action est utilisée, elle effectue une build Docker pour cette image. Ainsi, chaque déclencheur doit faire face à un délai pour créer le conteneur avant de le lancer. Avant de publier vos actions GitHub sur la Place de marché, vous devez :
- (automatiquement) Générer l’image Docker
- Envoyer (push) l’image Docker vers GitHub Container Registry (ou tout autre registre de conteneurs public)
- Modifiez l’action pour ne pas générer l’image, mais pour utiliser une image à partir d’un registre public.
# Rest of action.yml content removed for readability
# using Dockerfile
runs:
using: 'docker'
image: 'Dockerfile' # Change this line
# using container image from public registry
runs:
using: 'docker'
image: 'docker://ghcr.io/some-user/some-registry' # Starting with docker:// is important!!
Pour plus d’informations, consultez GitHub Docs : Utilisation du registre de conteneurs.
Voir aussi
- Hôte générique .NET
- Injection de dépendances dans .NET
- Valeurs des métriques de code
- Build GitHub Action open source dans .NET avec un workflow permettant de générer et d’envoyer (push) automatiquement l’image Docker.