Aracılığıyla paylaş


Öğretici: .NET ile GitHub Eylemi Oluşturma

GitHub Eylemi olarak kullanılabilecek bir .NET uygulaması oluşturmayı öğrenin. GitHub Actions , iş akışı otomasyonu ve bileşimini etkinleştirir. GitHub Actions ile GitHub'dan kaynak kodu derleyebilir, test edebilir ve dağıtabilirsiniz. Ayrıca eylemler, program aracılığıyla sorunlarla etkileşim kurma, çekme istekleri oluşturma, kod gözden geçirmeleri gerçekleştirme ve dalları yönetme olanağı sunar. GitHub Actions ile sürekli tümleştirme hakkında daha fazla bilgi için bkz . .NET oluşturma ve test etme.

Bu öğreticide aşağıdakilerin nasıl yapılacağını öğreneceksiniz:

  • GitHub Actions için bir .NET uygulaması hazırlama
  • Eylem girişlerini ve çıkışlarını tanımlama
  • İş akışı oluşturma

Önkoşullar

Uygulamanın amacı

Bu öğreticideki uygulama şu şekilde kod ölçümü analizi gerçekleştirir:

  • *.csproj ve *.vbproj proje dosyalarını tarama ve bulma.

  • Aşağıdakiler için bu projeler içinde bulunan kaynak kodu analiz etme:

    • Döngüsel karmaşıklık
    • Bakım dizini
    • Devralma derinliği
    • Sınıf ilişkilendirme
    • Kaynak kodun satır sayısı
    • Yaklaşık yürütülebilir kod satırları
  • CODE_METRICS.md dosyası oluşturma (veya güncelleştirme).

Uygulama, CODE_METRICS.md dosyasında yapılan değişikliklerle çekme isteği oluşturmakla sorumlu değildir. Bu değişiklikler iş akışı oluşturma işleminin bir parçası olarak yönetilir.

Bu öğreticideki kaynak koduna yapılan başvurularda uygulamanın bazı bölümleri kısa süreliğine atlanmıştır. Uygulama kodunun tamamı GitHub'da kullanılabilir.

Uygulamayı keşfedin

.NET konsol uygulaması, bağımsız değişkenleri nesnesine CommandLineParser ActionInputs ayrıştırmak için NuGet paketini kullanır.

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]);
        }
    }
}

Yukarıdaki eylem girişleri sınıfı, uygulamanın başarıyla çalışması için gerekli birkaç girişi tanımlar. Oluşturucu, geçerli yürütme ortamında varsa ortam değişkeni değerini yazar "GREETINGS" . Name ve Branch özellikleri ayrıştırılır ve sınırlandırılmış dizenin "/" son kesiminden atanır.

Tanımlı eylem girişleri sınıfıyla Program.cs dosyasına odaklanın.

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

Dosya Program kısa kullanım için basitleştirilmiştir. Örnek kaynağın tamamını keşfetmek için bkz . Program.cs. Mekanik, kullanmak için gereken ortak kodu gösterir:

Dış proje veya paket başvuruları kullanılabilir ve bağımlılık ekleme ile kaydedilebilir. Get<TService> örneği gerektiren IHost statik bir yerel işlevdir ve gerekli hizmetleri çözümlemek için kullanılır. Singleton ileCommandLine.Parser.Default, uygulama içinden argsbir parser örnek alır. Bağımsız değişkenler ayrıştırılamadıklarında, uygulama sıfır olmayan bir çıkış koduyla çıkar. Daha fazla bilgi için bkz . Eylemler için çıkış kodlarını ayarlama.

Args başarıyla ayrıştırıldığında, uygulama gerekli girişlerle doğru şekilde çağrıldı. Bu durumda, birincil işleve StartAnalysisAsync bir çağrı yapılır.

Çıkış değerleri yazmak için GitHub Actions: Bir çıkış parametresi ayarlama tarafından tanınan biçimi izlemeniz gerekir.

.NET uygulamasını GitHub Actions için hazırlama

GitHub Actions, iki uygulama geliştirme çeşitlemesi de destekler

  • JavaScript (isteğe bağlı olarak TypeScript)
  • Docker kapsayıcısı (Docker üzerinde çalışan tüm uygulamalar)

GitHub Eylemi'nin barındırıldığı sanal ortamda .NET yüklü olabilir veya olmayabilir. Hedef ortama nelerin önceden yüklendiği hakkında bilgi için bkz . GitHub Actions Sanal Ortamları. GitHub Actions iş akışlarından .NET CLI komutlarını çalıştırmak mümkün olsa da, daha tam olarak çalışır. NET tabanlı GitHub Action, uygulamayı kapsayıcıya almanızı öneririz. Daha fazla bilgi için bkz . .NET uygulamasını kapsayıcıya alma.

The Dockerfile

Dockerfile, görüntü oluşturmaya yönelik yönergeler kümesidir. .NET uygulamaları için Dockerfile genellikle bir çözüm dosyasının yanındaki dizinin kökünde yer alır.

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

Dekont

Bu öğreticideki .NET uygulaması, işlevselliğinin bir parçası olarak .NET SDK'sına dayanır. Dockerfile, öncekilerden bağımsız olarak yeni bir Docker katmanları kümesi oluşturur. SDK görüntüsüyle sıfırdan başlar ve önceki katman kümesinden derleme çıkışını ekler. İşlevselliklerinin bir parçası olarak .NET SDK gerektirmeyen uygulamalar için bunun yerine yalnızca .NET Çalışma Zamanı'na güvenmeleri gerekir. Bu, görüntünün boyutunu büyük ölçüde azaltır.

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

Uyarı

"Docker desteği ekle" işlevinden oluşturulan standart Dockerfile'dan farklı olduğundan Dockerfile içindeki her adıma dikkat edin. Özellikle, son birkaç adım, uygulamanın ENTRYPOINTyolunu değiştirecek yeni WORKDIR bir değer belirtmeyerek değişiklik gösterir.

Yukarıdaki Dockerfile adımları şunlardır:

  • temel görüntüsünü mcr.microsoft.com/dotnet/sdk:7.0 diğer ad build-envolarak ayarlama.
  • İçeriği kopyalama ve .NET uygulamasını yayımlama:
  • Kapsayıcıya etiket uygulama.
  • .NET SDK görüntüsünün geçişini oluşturma mcr.microsoft.com/dotnet/sdk:7.0
  • yayımlanan derleme çıkışını build-enviçinden kopyalama.
  • öğesini temsil dotnet /DotNet.GitHubAction.dlleden giriş noktasını tanımlama.

Bahşiş

içindeki mcr.microsoft.com MCR, "Microsoft Container Registry" anlamına gelir ve Microsoft'un resmi Docker hub'ından gelen genel kapsayıcı kataloğudur. Daha fazla bilgi için bkz . Microsoft syndicates kapsayıcı kataloğu.

Dikkat

SDK sürümünü sabitlemek için global.json dosyası kullanıyorsanız Dockerfile dosyanızda bu sürüme açıkça başvurmanız gerekir. Örneğin, SDK sürümünü 5.0.300sabitlemek için global.json kullandıysanız Dockerfile'ınız kullanmalıdırmcr.microsoft.com/dotnet/sdk:5.0.300. Bu, yeni bir küçük düzeltme yayınlandığında GitHub Actions'ın bozulmasını önler.

Eylem girişlerini ve çıkışlarını tanımlama

Uygulamayı keşfedin bölümünde sınıfı hakkında bilgi ActionInputs edindiyseniz. Bu nesne, GitHub Eylemi için girişleri temsil eder. GitHub'ın deponun bir GitHub Eylemi olduğunu fark etmek için, deponun kökünde bir action.yml dosyası olmalıdır.

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

Yukarıdaki action.yml dosyası aşağıdakileri tanımlar:

  • name GitHub Eyleminin ve description sayısı
  • brandingGitHub Market'te eyleminizi daha benzersiz bir şekilde tanımlamanıza yardımcı olmak için kullanılan .
  • inputssınıfıyla ActionInputs bire bir eşlenen ,
  • outputsiçinde öğesine yazılan Program ve İş akışı oluşturma işleminin bir parçası olarak kullanılan ,
  • GitHub'a runs uygulamanın bir docker uygulama olduğunu ve hangi bağımsız değişkenlerin iletildiğini bildiren düğüm

Daha fazla bilgi için bkz . GitHub Actions için meta veri söz dizimi.

Önceden tanımlanmış ortam değişkenleri

GitHub Actions ile varsayılan olarak birçok ortam değişkenine sahip olursunuz. Örneğin, değişken GITHUB_REF her zaman iş akışı çalıştırmasını tetikleyen dal veya etikete bir başvuru içerir. GITHUB_REPOSITORY sahibine ve depo adına sahiptir; örneğin, dotnet/docs.

Önceden tanımlanmış ortam değişkenlerini incelemeli ve uygun şekilde kullanmalısınız.

İş akışı oluşturma

.NET uygulaması kapsayıcılıyken ve eylem girişleri ve çıkışları tanımlandığında, eylemi kullanmaya hazırsınız demektir. GitHub Actions'ın kullanılabilmesi için GitHub Market'te yayımlanması gerekmez. İş akışları, bir deponun .github/workflows dizininde YAML dosyaları olarak tanımlanır.

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

Önemli

Kapsayıcılı GitHub Actions için kullanmanız runs-on: ubuntu-latestgerekir. Daha fazla bilgi için bkz . İş akışı söz dizimi jobs.<job_id>.runs-on.

Yukarıdaki iş akışı YAML dosyası üç birincil düğüm tanımlar:

  • name İş akışının. Bu ad, iş akışı durumu rozeti oluşturulurken de kullanılır.
  • Düğüm, on eylemin ne zaman ve nasıl tetiklenmiş olduğunu tanımlar.
  • Düğüm, jobs her işin içindeki çeşitli işleri ve adımları özetler. Tek tek adımlar GitHub Actions'i tüketir.

Daha fazla bilgi için bkz . İlk iş akışınızı oluşturma.

Düğüme steps odaklanarak, bileşim daha belirgindir:

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

, jobs.steps iş akışı bileşimini temsil eder. Adımlar sıralı, iletişimsel ve birleştirilebilir olacak şekilde düzenlenir. Adımları temsil eden çeşitli GitHub Actions ile her biri giriş ve çıkışlara sahip olan iş akışları oluşturulabilir.

Yukarıdaki adımlarda şunları gözlemleyebilirsiniz:

  1. Depo kullanıma alındı.

  2. el ile çalıştırıldığında iş akışı günlüğüne bir ileti yazdırılır.

  3. olarak dotnet-code-metricstanımlanan bir adım:

    • uses: dotnet/samples/github-actions/DotNet.GitHubAction@main , bu öğreticide kapsayıcılı .NET uygulamasının konumudur.
    • env , uygulamanın yürütülmesinde yazdırılan bir ortam değişkeni "GREETING"oluşturur.
    • with gerekli eylem girişlerinin her birini belirtir.
  4. adlı Create pull request koşullu bir adım, adım değeriyle trueçıkış parametresini updated-metrics belirttiğinde dotnet-code-metrics çalışır.

Önemli

GitHub, şifrelenmiş gizli dizilerin oluşturulmasına olanak tanır. Gizli diziler, söz dizimi kullanılarak iş akışı oluşturmada ${{ secrets.SECRET_NAME }} kullanılabilir. GitHub Eylemi bağlamında, varsayılan olarak otomatik olarak doldurulan bir GitHub belirteci vardır: ${{ secrets.GITHUB_TOKEN }}. Daha fazla bilgi için bkz . GitHub Actions için bağlam ve ifade söz dizimi.

Hepsini bir araya getirin

dotnet/samples GitHub deposu, bu öğreticideki uygulama da dahil olmak üzere birçok .NET örnek kaynak kodu projesine ev sahipliği eder.

Oluşturulan CODE_METRICS.md dosyası gezinilebilir. Bu dosya analiz ettiği projelerin hiyerarşisini temsil eder. Her projenin bir üst düzey bölümü ve iç içe nesneler için en yüksek döngüsel karmaşıklığın genel durumunu temsil eden bir emojisi vardır. Dosyada gezinirken her bölüm, her alanın özetini içeren detaya gitme fırsatlarını kullanıma sunar. Markdown,ek kolaylık sağlamak için daraltılabilir bölümlere sahiptir.

Hiyerarşi şu şekilde ilerler:

  • Derlemeye proje dosyası
  • Derlemeden ad alanına
  • Ad alanını adlandırılmış türe
  • Her adlandırılmış türün bir tablosu vardır ve her tabloda aşağıdakiler vardır:
    • Alanlar, yöntemler ve özellikler için satır numaralarına bağlantılar
    • Kod ölçümleri için bireysel derecelendirmeler

Uygulama

İş akışı, dal için eylemin push main çalıştırılacak şekilde tetiklendiğini belirtiron. Çalıştırıldığında GitHub'daki Eylemler sekmesi yürütmesinin canlı günlük akışını bildirir. Çalıştırmadan örnek bir günlük aşağıda verilmiştir .NET code metrics :

.NET code metrics - GitHub Actions log

Performans iyileştirmeleri

Örneği takip ettiyseniz, bu eylem her kullanıldığında bu görüntü için bir docker derlemesi gerçekleştireceğini fark etmiş olabilirsiniz. Bu nedenle, her tetikleyici çalıştırmadan önce kapsayıcıyı derlemek için biraz zaman alır. GitHub Actions'ınızı markette yayınlamadan önce şunları yapmalısınız:

  1. (otomatik olarak) Docker görüntüsünü oluşturma
  2. Docker görüntüsünü GitHub Container Registry'ye (veya başka bir genel kapsayıcı kayıt defterine) gönderme
  3. Eylemi, görüntüyü derlemek için değil, genel kayıt defterinden bir görüntü kullanacak şekilde değiştirin.
# 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!!

Daha fazla bilgi için bkz . GitHub Belgeleri: Kapsayıcı kayıt defteriyle çalışma.

Ayrıca bkz.

Sonraki adımlar