Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Meer informatie over het maken van een .NET-app die kan worden gebruikt als een GitHub Action. GitHub Actions maken werkstroomautomatisering en -samenstelling mogelijk. Met GitHub Actions kunt u broncode bouwen, testen en implementeren vanuit GitHub. Daarnaast bieden acties de mogelijkheid om programmatisch te communiceren met issues, pull requests te maken, codebeoordelingen uit te voeren en branches te beheren. Zie .NET bouwen en testen voor meer informatie over continue integratie met GitHub Actions.
In deze handleiding leer je hoe je:
- Een .NET-app voorbereiden voor GitHub Actions
- Actie-invoer en -uitvoer definiëren
- Een werkstroom opstellen
Vereiste voorwaarden
- Een GitHub-account
- De .NET 6 SDK of hoger
- Een .NET geïntegreerde ontwikkelomgeving (IDE)
- U kunt de Visual Studio IDE gerust gebruiken
De intentie van de app
De app in deze zelfstudie voert metrische codeanalyse uit op:
Scannen en ontdekken van *.csproj en *.vbproj projectbestanden.
De gedetecteerde broncode in deze projecten analyseren voor:
- Cyclomatische complexiteit
- Index voor onderhoudbaarheid
- Diepte van erfenis
- Klassekoppeling
- Aantal regels broncode
- Geschatte aantal regels uitvoerbare code
Een CODE_METRICS.md-bestand maken (of bijwerken).
De app is niet verantwoordelijk voor het maken van een pull-aanvraag met de wijzigingen in het bestand CODE_METRICS.md . Deze wijzigingen worden beheerd als onderdeel van de werkstroomsamenstelling.
Verwijzingen naar de broncode in deze zelfstudie bevatten gedeelten van de app die ter beknoptheid zijn weggelaten. De volledige app-code is beschikbaar op GitHub.
De app verkennen
De .NET-console-app maakt gebruik van het CommandLineParser NuGet-pakket om argumenten in het ActionInputs object te parseren.
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]);
}
}
}
De voorgaande inputklasse definieert verschillende vereiste invoer voor de app om succesvol te draaien. De constructor schrijft de waarde van de "GREETINGS" omgevingsvariabele als deze beschikbaar is in de huidige uitvoeringsomgeving. De Name en Branch eigenschappen worden geparseerd en toegewezen vanuit het laatste segment van een "/" gescheiden tekenreeks.
Focus op het Program.cs-bestand met de gedefinieerde actie-invoerklasse.
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);
}
Het Program bestand is vereenvoudigd voor beknoptheid, om de volledige voorbeeldbron te verkennen, zie Program.cs. De mechanismen laten de standaardcode zien die vereist is voor gebruik:
Externe verwijzingen naar projecten of pakketten kunnen worden gebruikt en geregistreerd bij dependency injection. Het Get<TService> is een statische lokale functie, waarvoor het IHost exemplaar is vereist en wordt gebruikt om vereiste services op te lossen. Met de CommandLine.Parser.Default singleton haalt de app een parser exemplaar op van de args. Wanneer de argumenten niet kunnen worden geparseerd, wordt de app afgesloten met een afsluitcode die niet nul is. Zie Afsluitcodes instellen voor acties voor meer informatie.
Wanneer de argumenten zijn verwerkt, wordt de app correct aangeroepen met de nodige gegevens. In dit geval wordt een aanroep naar de primaire functionaliteit StartAnalysisAsync uitgevoerd.
Als u uitvoerwaarden wilt schrijven, moet u de indeling volgen die wordt herkend door GitHub Actions: een uitvoerparameter instellen.
De .NET-app voorbereiden voor GitHub Actions
GitHub Actions ondersteunen twee variaties van app-ontwikkeling, ofwel
- JavaScript (optioneel TypeScript)
- Docker-container (elke app die wordt uitgevoerd in Docker)
De virtuele omgeving waarop de GitHub Action wordt gehost, heeft .NET al dan niet geïnstalleerd. Zie GitHub Actions Virtual Environments voor informatie over wat vooraf is geïnstalleerd in de doelomgeving. Hoewel het mogelijk is om .NET CLI-opdrachten uit te voeren vanuit de GitHub Actions-werkstromen, raden we voor een beter functionerende .NET-gebaseerde GitHub Action aan om de app te containeriseren. Zie Een .NET-app containeriseren voor meer informatie.
Het Dockerfile
Een Dockerfile is een set instructies voor het bouwen van een image. Voor .NET-toepassingen bevindt het Dockerfile zich meestal in de hoofdmap van de map naast een oplossingsbestand.
# 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" ]
Opmerking
De .NET-app in deze zelfstudie is afhankelijk van de .NET SDK als onderdeel van de functionaliteit. Het Dockerfile maakt een nieuwe set Docker-lagen, onafhankelijk van de vorige lagen. Het begint vanaf nul met de SDK-afbeelding en voegt de build-uitvoer van de vorige reeks lagen toe. Voor toepassingen die de .NET SDK niet nodig hebben als onderdeel van hun functionaliteit, moeten ze alleen afhankelijk zijn van de .NET Runtime. Dit vermindert de grootte van de afbeelding aanzienlijk.
FROM mcr.microsoft.com/dotnet/runtime:7.0
Waarschuwing
Let goed op elke stap in het Dockerfile, omdat deze verschilt van de standaard Dockerfile die is gemaakt met de functionaliteit Docker-ondersteuning toevoegen. In het bijzonder variëren de laatste stappen door geen nieuwe WORKDIR op te geven die het pad naar de app ENTRYPOINTzou wijzigen.
De voorgaande Dockerfile-stappen omvatten:
- De basisafbeelding
mcr.microsoft.com/dotnet/sdk:7.0instellen als de aliasbuild-env. - De inhoud kopiëren en de .NET-app publiceren:
- De app wordt gepubliceerd met behulp van de
dotnet publishopdracht.
- De app wordt gepubliceerd met behulp van de
- Labels toepassen op de container.
- Het herstructureren van het .NET SDK-beeld van
mcr.microsoft.com/dotnet/sdk:7.0 - Het kopiëren van de gepubliceerde build-uitvoer van de
build-env. - Het beginpunt definiëren, dat door
dotnet /DotNet.GitHubAction.dllwordt gedelegeerd.
Aanbeveling
De MCR in mcr.microsoft.com staat voor 'Microsoft Container Registry' en is de gesyndiceerde containercatalogus van Microsoft van de officiële Docker-hub. Zie de containercatalogus van Microsoft syndicates voor meer informatie.
Waarschuwing
Als u een global.json-bestand gebruikt om de SDK-versie vast te maken, moet u expliciet naar die versie verwijzen in uw Dockerfile. Als u bijvoorbeeld global.json hebt gebruikt om de SDK-versie 5.0.300 te vergrendelen, moet uw Dockerfilemcr.microsoft.com/dotnet/sdk:5.0.300 gebruiken. Dit voorkomt dat de GitHub Actions worden onderbroken wanneer er een nieuwe kleine revisie wordt uitgebracht.
Actie-invoer en -uitvoer definiëren
In de sectie De app verkennen hebt u meer geleerd over de ActionInputs klas. Dit object vertegenwoordigt de invoer voor de GitHub-actie. GitHub moet een action.yml bestand in de hoofdmap van de opslagplaats hebben om te kunnen herkennen dat de opslagplaats een GitHub Action is.
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 }}
In het voorgaande action.yml bestand wordt het volgende gedefinieerd:
- De
nameendescriptionvan de GitHub Action - De
branding, die wordt gebruikt in de GitHub Marketplace om uw actie unieker te identificeren - De
inputs, die een-op-een overeenkomt met deActionInputsklasse - De
outputs, waarnaar wordt geschreven in deProgramen wordt gebruikt als onderdeel van werkstroomsamenstelling - Het
runsknooppunt, dat GitHub vertelt dat de app eendockertoepassing is en welke argumenten aan de app moeten worden doorgegeven
Zie De syntaxis van metagegevens voor GitHub Actions voor meer informatie.
Vooraf gedefinieerde omgevingsvariabelen
Met GitHub Actions krijgt u standaard veel omgevingsvariabelen . De variabele GITHUB_REF bevat bijvoorbeeld altijd een verwijzing naar de vertakking of tag die de werkstroom heeft geactiveerd.
GITHUB_REPOSITORY heeft de naam van de eigenaar en de opslagplaats, dotnet/docsbijvoorbeeld.
U moet de vooraf gedefinieerde omgevingsvariabelen verkennen en dienovereenkomstig gebruiken.
Werkstroomsamenstelling
Nu de .NET-app is gecontaineriseerd en de actie-invoer en -uitvoer zijn gedefinieerd, kunt u de actie gebruiken. GitHub Actions hoeven niet te worden gepubliceerd in de GitHub Marketplace om te worden gebruikt. Werkstromen worden gedefinieerd in de map .github/workflows van een opslagplaats als YAML-bestanden.
# 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.'
Belangrijk
Voor in containers geplaatste GitHub Actions moet u gebruiken runs-on: ubuntu-latest. Zie Werkstroomsyntaxis jobs.<job_id>.runs-onvoor meer informatie.
In het voorgaande YAML-werkstroombestand worden drie primaire knooppunten gedefinieerd:
- De
namewerkstroom. Deze naam wordt ook gebruikt bij het maken van een werkstroomstatusbadge. - Het
onknooppunt definieert wanneer en hoe de actie wordt geactiveerd. - Het
jobsknooppunt bevat een overzicht van de verschillende taken en stappen binnen elke taak. Afzonderlijke stappen gebruiken GitHub Actions.
Zie Uw eerste werkstroom maken voor meer informatie.
Focus op het steps knooppunt, de samenstelling is duidelijker:
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.'
De jobs.steps vertegenwoordigt de werkstroomsamenstelling. Stappen worden zodanig ingedeeld dat ze opeenvolgend, communicatief en samenstelbaar zijn. Met verschillende GitHub Actions die stappen vertegenwoordigen, elk met invoer en uitvoer, kunnen werkstromen worden samengesteld.
In de voorgaande stappen kunt u het volgende bekijken:
De opslagplaats is uitgecheckt.
Er wordt een bericht weergegeven in het workflowlogboek wanneer het handmatig wordt uitgevoerd.
Een stap die is geïdentificeerd als
dotnet-code-metrics:-
uses: dotnet/samples/github-actions/DotNet.GitHubAction@mainis de locatie van de gecontaineriseerde .NET-app in deze instructie. -
envmaakt een omgevingsvariabele"GREETING"die wordt afgedrukt in de uitvoering van de app. -
withspecificeert elk van de vereiste invoer voor acties.
-
Een voorwaardelijke stap, genaamd
Create pull request, wordt uitgevoerd wanneer de stapdotnet-code-metricseen uitvoerparameterupdated-metricsspecificeert met een waarde vantrue.
Belangrijk
Met GitHub kunt u versleutelde geheimen maken. Geheimen kunnen worden gebruikt in werkstroomsamenstelling, met behulp van de ${{ secrets.SECRET_NAME }} syntaxis. In de context van een GitHub Action is er een GitHub-token dat standaard automatisch wordt ingevuld: ${{ secrets.GITHUB_TOKEN }} Zie context- en expressiesyntaxis voor GitHub Actions voor meer informatie.
Alles samenvoegen
De GitHub-opslagplaats dotnet/samples is de thuisbasis van veel .NET-voorbeeldbroncodeprojecten, waaronder de app in deze zelfstudie.
Het gegenereerde bestand CODE_METRICS.md is bevaarbaar. Dit bestand vertegenwoordigt de hiërarchie van de projecten die worden geanalyseerd. Elk project heeft een sectie op het hoogste niveau en een emoji die de algehele status van de hoogste cyclomatische complexiteit voor geneste objecten vertegenwoordigt. Wanneer u door het bestand navigeert, worden in elke sectie inzoommogelijkheden weergegeven met een samenvatting van elk gebied. Markdown heeft samenvouwbare secties als een extra handige functie.
De hiërarchie loopt van:
- Projectbestand naar assemblage
- Assembly naar naamruimte
- Naamruimte naar benoemd type
- Elk benoemd type heeft een tabel en elke tabel heeft:
- Koppelingen naar regelnummers voor velden, methoden en eigenschappen
- Afzonderlijke classificaties voor metrische codegegevens
In actie
De werkstroom geeft aan dat on een push naar de main vertakking, de actie wordt geactiveerd om uit te voeren. Wanneer het wordt uitgevoerd, rapporteert het tabblad Acties in GitHub de livelogboekstream van de uitvoering. Hier volgt een voorbeeldlogboek van de .NET code metrics uitvoering:
Prestatieverbeteringen
Als u het voorbeeld hebt gevolgd, hebt u misschien gemerkt dat elke keer dat deze actie wordt gebruikt, er een docker build voor dat image wordt uitgevoerd. Dus, voor elke trigger is enige tijd nodig om de container op te bouwen voordat deze wordt uitgevoerd. Voordat u uw GitHub Actions publiceert in de marketplace, moet u het volgende doen:
- Bouw automatisch de Docker-image
- Push het Docker-image naar het GitHub-containerregister (of een ander openbaar containerregister)
- Wijzig de actie om de image niet te bouwen, maar om een image uit een openbare registry te gebruiken.
# 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!!
Zie GitHub Docs voor meer informatie: Werken met het containerregister.
Zie ook
- .NET Generieke Host
- Afhankelijkheidsinjectie in .NET
- Code-metriek waarden
- Open-source GitHub Action-build in .NET met een workflow voor het automatisch bouwen en pushen van de docker-image.