Sdílet prostřednictvím


Kurz: Vytvoření akce GitHubu pomocí .NET

Zjistěte, jak vytvořit aplikaci .NET, která se dá použít jako akce GitHubu. GitHub Actions umožňuje automatizaci a složení pracovních postupů. Pomocí GitHub Actions můžete vytvářet, testovat a nasazovat zdrojový kód z GitHubu. Akce navíc zpřístupňují možnost programově pracovat s problémy, vytvářet žádosti o přijetí změn, provádět kontroly kódu a spravovat větve. Další informace o kontinuální integraci s GitHub Actions najdete v tématu Sestavování a testování .NET.

V tomto návodu se naučíte, jak:

  • Příprava aplikace .NET pro GitHub Actions
  • Definování vstupů a výstupů akcí
  • Vytvoření pracovního postupu

Požadavky

Záměr aplikace

Aplikace v tomto kurzu provádí analýzu metrik kódu pomocí:

  • Skenování a zjišťování souborů projektu *.csproj a *.vbproj .

  • Analýza zjištěného zdrojového kódu v rámci těchto projektů pro:

    • Cyklomaticová složitost
    • Index udržovatelnosti
    • Hloubka dědičnosti
    • Párování tříd
    • Počet řádků zdrojového kódu
    • Přibližné řádky spustitelného kódu
  • Vytvoření (nebo aktualizace) souboru CODE_METRICS.md

Aplikace není odpovědná za vytvoření pull requestu pro změny v souboru CODE_METRICS.md. Tyto změny se spravují jako součást složení pracovního postupu.

Odkazy na zdrojový kód v tomto kurzu obsahují části aplikace, které jsou pro stručnost vynechány. Kompletní kód aplikace je k dispozici na GitHubu.

Prozkoumání aplikace

Konzolová aplikace .NET používá CommandLineParser balíček NuGet k analýze argumentů do objektu 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]);
        }
    }
}

Předchozí třída vstupů akcí definuje několik požadovaných vstupů pro úspěšné spuštění aplikace. Konstruktor zapíše "GREETINGS" hodnotu proměnné prostředí, pokud je k dispozici v aktuálním spouštěcím prostředí. Vlastnosti Name a Branch se analyzují a přiřazují z posledního segmentu řetězce odděleného "/".

S definovanou třídou vstupů akcí se zaměřte na soubor 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);
}

Soubor Program je zjednodušený pro stručnost, abyste prozkoumali úplný ukázkový zdroj, viz Program.cs. Tato mechanika demonstruje často používaný kód potřebný k použití:

Odkazy na externí projekt nebo balíček lze použít a zaregistrovat pomocí injektáže závislostí. Jedná se Get<TService> o statickou místní funkci, která vyžaduje IHost instanci a slouží k vyřešení požadovaných služeb. Pomocí CommandLine.Parser.Default singletonu získá parser aplikace instanci z args. Pokud argumenty nelze analyzovat, aplikace se ukončí nenulovým ukončovacím kódem. Další informace naleznete v tématu Nastavení výstupních kódů pro akce.

Když jsou argumenty úspěšně zpracovány, aplikace byla spuštěna správně s potřebnými vstupy. V tomto případě se provede volání primární funkce StartAnalysisAsync .

Pokud chcete zapisovat výstupní hodnoty, musíte postupovat podle formátu, který GitHub Actions rozpozná: Nastavení výstupního parametru.

Příprava aplikace .NET pro GitHub Actions

GitHub Actions podporuje dvě varianty vývoje aplikací, a to buď

  • JavaScript (volitelně TypeScript)
  • Kontejner Dockeru (libovolná aplikace, která běží v Dockeru)

Virtuální prostředí, ve kterém je akce GitHubu hostovaná, může nebo nemusí mít nainstalovanou technologii .NET. Informace o tom, co je předinstalované v cílovém prostředí, najdete v tématu Virtuální prostředí GitHub Actions. I když je možné spouštět příkazy rozhraní příkazového řádku .NET z pracovních postupů GitHub Actions, pro plně funkční GitHub akci založenou na .NET doporučujeme aplikaci kontejnerizovat. Další informace najdete v tématu Kontejnerizace aplikace .NET.

Soubor Dockerfile

Soubor Dockerfile je sada instrukcí pro sestavení image. V případě aplikací .NET se soubor Dockerfile obvykle nachází v kořenovém adresáři vedle souboru řešení.

# 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" ]

Poznámka:

Aplikace .NET v tomto kurzu spoléhá na sadu .NET SDK jako součást jeho funkcí. Soubor Dockerfile vytvoří novou sadu vrstev Dockeru nezávisle na předchozích vrstvách. Začíná úplně od začátku s imagí sady SDK a přidá výstup sestavení z předchozí sady vrstev. U aplikací, které nevyžadují sadu .NET SDK jako součást jejich funkcí, by se místo toho měly spoléhat pouze na modul runtime .NET. Tím se výrazně zmenšuje velikost obrázku.

FROM mcr.microsoft.com/dotnet/runtime:7.0

Výstraha

Věnujte pozornost každému kroku v souboru Dockerfile, protože se liší od standardního souboru Dockerfile vytvořeného z funkce "přidání podpory Dockeru". Konkrétně se posledních několik kroků liší tím, že nezadáte novou WORKDIR, která by změnila cestu k aplikaci ENTRYPOINT.

Mezi předchozí kroky souboru Dockerfile patří:

  • Nastavení základního image z mcr.microsoft.com/dotnet/sdk:7.0 jako alias build-env.
  • Kopírování obsahu a publikování aplikace .NET:
  • Použití štítků na kontejner
  • Přenos image sady .NET SDK z mcr.microsoft.com/dotnet/sdk:7.0
  • Kopírování publikovaného výstupu sestavení z objektu build-env.
  • Definování vstupního bodu, který deleguje na dotnet /DotNet.GitHubAction.dll.

Návod

MCR mcr.microsoft.com je zkratka pro Microsoft Container Registry a je syndikovaný katalog kontejnerů Microsoftu z oficiálního centra Dockeru. Další informace naleznete v tématu Syndikace katalogu kontejnerů Microsoft.

Upozornění

Pokud k připnutí verze sady SDK použijete souborglobal.json , měli byste explicitně odkazovat na tuto verzi v souboru Dockerfile. Pokud jste například použili global.json k připnutí verze 5.0.300sady SDK, měl by váš soubor Dockerfile použít mcr.microsoft.com/dotnet/sdk:5.0.300. Tím se zabrání porušení GitHub Actions při vydání nové dílčí revize.

Definování vstupů a výstupů akcí

V sekci Prozkoumat aplikaci jste se dozvěděli o třídě ActionInputs. Tento objekt představuje vstupy akce GitHubu. Aby GitHub rozpoznal, že úložiště je akce GitHubu, musíte mít v kořenovém adresáři úložiště soubor action.yml .

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 }}

Předchozí soubor action.yml definuje:

  • Akce GitHubu name a description
  • Nástroj branding, který se používá na GitHub Marketplace k jedinečnější identifikaci vaší akce
  • , inputskterý mapuje 1:1 s ActionInputs třídou
  • outputs, který je zapsán do Program a používá se jako součást kompozice pracovního postupu
  • Uzel runs, který GitHubu říká, že jde o docker aplikaci a jaké argumenty jí mají být předány.

Další informace najdete v tématu Syntaxe metadat pro GitHub Actions.

Předdefinované proměnné prostředí

Pomocí GitHub Actions získáte ve výchozím nastavení spoustu proměnných prostředí . Proměnná GITHUB_REF bude například vždy obsahovat odkaz na větev nebo značku, která aktivovala spuštění pracovního postupu. GITHUB_REPOSITORY má název vlastníka a úložiště, například dotnet/docs.

Měli byste prozkoumat předem definované proměnné prostředí a odpovídajícím způsobem je používat.

Složení pracovního postupu

S kontejnerizovanou aplikací .NET a definovanými vstupy a výstupy akce můžete využívat akci. Aby bylo možné gitHub Actions použít, není nutné publikovat na GitHub Marketplace. Pracovní postupy se definují v adresáři .github/workflows úložiště jako soubory 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.'

Důležité

Pro kontejnerizované GitHub Actions musíte použít runs-on: ubuntu-latest. Další informace naleznete v tématu Syntaxe jobs.<job_id>.runs-onpracovního postupu .

Předchozí soubor YAML pracovního postupu definuje tři primární uzly:

  • Pracovní name postup. Tento název se také používá při vytváření odznáček stavu pracovního postupu.
  • Uzel on definuje, kdy a jak se akce aktivuje.
  • Uzel jobs popisuje různé úlohy a kroky v rámci každé úlohy. Jednotlivé kroky využívají GitHub Actions.

Další informace naleznete v tématu Vytvoření prvního pracovního postupu.

Zaměření na steps uzel, složení je jasnější:

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.'

Představuje jobs.stepssložení pracovního postupu. Kroky jsou orchestrovány tak, aby byly sekvenční, komunikační a kompozibilní. S různými akcemi GitHub Actions představujícími kroky se dají skládat pracovní postupy, které mají vstupy a výstupy.

V předchozích krocích můžete sledovat:

  1. Úložiště je vycheckoutováno.

  2. Při ručním spuštění se do protokolu pracovního postupu vytiskne zpráva.

  3. Krok označený jako dotnet-code-metrics:

    • uses: dotnet/samples/github-actions/DotNet.GitHubAction@main je umístěním aplikace .NET vytvořené v kontejneru v tomto tutoriálu.
    • env vytvoří proměnnou prostředí "GREETING", která je vytištěna při provádění aplikace.
    • with určuje každý z požadovaných vstupů akce.
  4. Podmíněný krok s názvem Create pull request se spustí, když dotnet-code-metrics krok určuje výstupní parametr updated-metrics s hodnotou true.

Důležité

GitHub umožňuje vytvářet šifrované tajné kódy. Tajné údaje lze použít v rámci skládání pracovních procesů pomocí syntaxe ${{ secrets.SECRET_NAME }}. V kontextu akce GitHubu existuje token GitHubu, který se ve výchozím nastavení automaticky vyplní: ${{ secrets.GITHUB_TOKEN }}. Další informace najdete v tématu Kontextová syntaxe a syntaxe výrazů pro GitHub Actions.

Dejte to všechno dohromady

Úložiště dotnet/samples GitHubu je domovem mnoha projektů zdrojového kódu .NET, včetně aplikace v tomto kurzu.

Vygenerovaný soubor CODE_METRICS.md je možné procházet. Tento soubor představuje hierarchii projektů, které analyzoval. Každý projekt má sekci nejvyšší úrovně a emoji, který představuje celkový stav nejvyšší cyklomatické složitosti pro vnořené objekty. Při procházení souboru každá část zveřejňuje příležitosti přechodu k podrobnostem se souhrnem jednotlivých oblastí. Markdown má sbalitelné sekce pro větší pohodlí.

Hierarchie postupuje od:

  • Soubor projektu do sestavení
  • Sestavení do oboru názvů
  • Obor názvů pro pojmenovaný typ
  • Každý pojmenovaný typ má tabulku a každá tabulka má:
    • Odkazy na čísla řádků pro pole, metody a vlastnosti
    • Individuální hodnocení metrik kódu

V akci

Pracovní postup určuje, že onpushmain větev se aktivuje ke spuštění akce. Když se spustí, na kartě Akce na GitHubu bude zobrazen živý stream protokolu jeho spuštění. Tady je příklad protokolu z .NET code metrics běhu:

Metriky kódu .NET – protokol GitHub Actions

Vylepšení výkonu

Pokud jste postupovali podle ukázky, možná jste si všimli, že při každém použití této akce provede sestavení Dockeru pro tuto image. Každá spoušť musí počkat na sestavení kontejneru před jeho spuštěním. Než gitHub Actions vydáte na marketplace, měli byste:

  1. (automaticky) Vytvořte image Dockeru
  2. Nahrání Docker image do služby GitHub Container Registry (nebo jiného veřejného registru kontejnerů)
  3. Změňte akci tak, aby se image nevytvořela, ale aby se používala image z veřejného registru.
# 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!!

Další informace najdete v dokumentaci GitHubu: Práce s registrem kontejneru.

Viz také

Další kroky