Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Узнайте, как создать приложение .NET, которое можно использовать в качестве действия GitHub. GitHub Actions обеспечивает автоматизацию и композицию рабочих процессов. С помощью GitHub Actions можно создавать, тестировать и развертывать исходный код из GitHub. Кроме того, действия предоставляют возможность программного взаимодействия с задачами, создания pull request, выполнения проверок кода и управления ветками. Дополнительные сведения о непрерывной интеграции с GitHub Actions см. в статье "Создание и тестирование .NET".
В этом руководстве вы узнаете, как:
- Подготовка приложения .NET для GitHub Actions
- Определение входных и выходных данных действий
- Создание рабочего процесса
Предпосылки
- Учетная запись GitHub
- Пакет SDK для .NET 6 или более поздней версии
- Интегрированная среда разработки .NET (IDE)
- Вы можете использовать интегрированную среду разработки Visual Studio
Намерение приложения
Приложение в этом руководстве выполняет анализ метрик кода следующим образом:
Сканирование и обнаружение файлов проекта *.csproj и *.vbproj .
Анализ обнаруженного исходного кода в этих проектах:
- Цикломатическая сложность
- Индекс удобства обслуживания
- Глубина наследования
- Связывание классов
- Количество строк исходного кода
- Приблизительные строки исполняемого кода
Создание (или обновление) файла CODE_METRICS.md .
Приложение не отвечает за создание pull-запроса с изменениями в файле CODE_METRICS.md. Эти изменения управляются как часть композиции рабочего процесса.
Ссылки на исходный код в этом руководстве содержат части приложения, пропущенные для краткости. Полный код приложения доступен на сайте GitHub.
Изучение приложения
Консольное приложение .NET использует CommandLineParser пакет NuGet для анализа аргументов в 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]);
}
}
}
Предыдущий класс входных данных действия определяет несколько необходимых входных данных для успешного выполнения приложения. Конструктор записывает значение переменной "GREETINGS" среды, если он доступен в текущей среде выполнения.
Name и Branch свойства анализируются и присваиваются из последнего сегмента строки с разделителями, разделенной "/".
С использованием определенного класса входных данных действий сосредоточьтесь на файле 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);
}
Файл Program упрощен для краткости, чтобы просмотреть полный пример источника, см. Program.cs. Существующая механика демонстрирует стандартный код, который необходим для использования.
Внешние ссылки на проект или пакет можно использовать и зарегистрировать с помощью внедрения зависимостей. Это Get<TService> статическая локальная функция, которая требует IHost экземпляра и используется для разрешения необходимых служб. С одиночным CommandLine.Parser.Default приложение получает экземпляр parser из args. Если аргументы не удается разобрать, приложение завершает работу с ненулевым кодом завершения. Дополнительные сведения см. в разделе "Настройка кодов выхода для действий".
После успешного разбора аргументов приложение было вызвано корректно с необходимыми входными данными. В этом случае выполняется вызов основной функции StartAnalysisAsync .
Чтобы записать выходные значения, необходимо выполнить формат, распознанный GitHub Actions: задание выходного параметра.
Подготовка приложения .NET для GitHub Actions
GitHub Actions поддерживает два варианта разработки приложений.
- JavaScript (необязательно TypeScript)
- Контейнер Docker (любое приложение, работающее в Docker)
Виртуальная среда, в которой размещено действие GitHub, может иметь установленную .NET или нет. Сведения о том, что предустановлено в целевой среде, см. в виртуальных средах GitHub Actions. Хотя можно запускать команды .NET CLI из рабочих процессов GitHub Actions, для более полного функционирования GitHub Actions, основанных на .NET, рекомендуется контейнеризировать приложение. Дополнительные сведения см. в разделе "Контейнеризация приложения .NET".
Файл Dockerfile
Dockerfile — это набор инструкций по созданию образа. Для приложений .NET файл Dockerfile обычно находится в корне каталога рядом с файлом решения.
# 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" ]
Замечание
Приложение .NET в этом руководстве использует пакет SDK для .NET в рамках его функциональных возможностей. Dockerfile создает новый набор слоев Docker, не зависящий от предыдущих. Он начинается с нуля с образа пакета SDK и добавляет выходные данные сборки из предыдущего набора слоев. Для приложений, которые не требуют пакета SDK для .NET в рамках их функциональных возможностей, они должны полагаться только на среду выполнения .NET. Это значительно сокращает размер изображения.
FROM mcr.microsoft.com/dotnet/runtime:7.0
Предупреждение
Обратите особое внимание на каждый шаг в Dockerfile, так как он отличается от стандартного Файла Dockerfile , созданного из функции "добавление поддержки Docker". В частности, последние несколько шагов различаются тем, что не указан новый WORKDIR, который изменил бы путь к ENTRYPOINT приложения.
Ниже приведены предыдущие шаги Dockerfile :
- Задание базового образа в
mcr.microsoft.com/dotnet/sdk:7.0качестве псевдонимаbuild-env. - Копирование содержимого и публикация приложения .NET:
- Приложение публикуется с помощью
dotnet publishкоманды.
- Приложение публикуется с помощью
- Применение меток к контейнеру.
- Ретрансляция образа пакета SDK для .NET из
mcr.microsoft.com/dotnet/sdk:7.0 - Копирование опубликованного результата сборки из
build-env. - Определение точки входа, которая делегирует на
dotnet /DotNet.GitHubAction.dll.
Подсказка
MCR в mcr.microsoft.com означает "Реестр контейнеров Microsoft" и является каталогом контейнеров, входящим в синдикацию от Microsoft через официальный хаб Docker. Дополнительные сведения см. в каталоге контейнеров Microsoft Syndicates.
Caution
Если вы используете файл global.json для закрепления версии SDK, необходимо явно ссылаться на эту версию в Dockerfile. Если вы использовали global.json для закрепления версии пакета SDK 5.0.300, следует использовать Dockerfilemcr.microsoft.com/dotnet/sdk:5.0.300. Это предотвращает сбой GitHub Actions при выпуске новой минорной версии.
Определение входных и выходных данных действий
В разделе "Изучение приложения " вы узнали о ActionInputs классе. Этот объект представляет входные данные для действия GitHub. Чтобы GitHub распознал, что репозиторий является действием GitHub, необходимо иметь файл 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 }}
Указанный выше файл action.yml определяет следующее:
-
nameиdescriptionдействия GitHub - Элемент
branding, который используется в GitHub Marketplace для уникальной идентификации вашего действия - Объект
inputs, который соответствует один к одному классуActionInputs - Объект
outputs, который записывается вProgramи используется как часть композиции рабочего процесса. - Узел
runs, который сообщает GitHub, что это приложениеdockerи какие аргументы нужно передать ему
Дополнительные сведения см. в синтаксисе метаданных для GitHub Actions.
Предопределенные переменные среды
С помощью GitHub Actions вы получите множество переменных среды по умолчанию. Например, переменная GITHUB_REF всегда будет содержать ссылку на ветвь или тег, запустившие выполнение рабочего процесса.
GITHUB_REPOSITORY имеет имя владельца и репозитория, например dotnet/docs.
Необходимо изучить предварительно определенные переменные среды и использовать их соответствующим образом.
Состав рабочего процесса
При контейнеризации приложения .NET и определении входных и выходных данных действия, вы готовы использовать действие. Для использования Actions GitHub не требуется их публикация в GitHub Marketplace. Рабочие процессы определяются в каталоге github/workflows репозитория в виде файлов 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.'
Это важно
Для контейнерных действий GitHub необходимо использовать runs-on: ubuntu-latest. Дополнительные сведения см. в синтаксисе jobs.<job_id>.runs-onрабочего процесса.
Предыдущий файл YAML рабочего процесса определяет три основных узла:
-
nameрабочего процесса. Это имя также используется при создании индикатора состояния рабочего процесса. - Узел
onопределяет, когда и как активируется действие. - Узел
jobsописывает различные задания и шаги в каждом задании. Отдельные шаги потребляют GitHub Actions.
Дополнительные сведения см. в статье "Создание первого рабочего процесса".
Фокусируясь на steps узле, композиция более очевидна:
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состав рабочего процесса. Шаги оркестрируются таким образом, чтобы они были последовательными, коммуникатными и компонуемыми. С помощью различных действий GitHub Actions, представляющих шаги, каждый из которых имеет входные и выходные данные, рабочие процессы можно создавать.
На предыдущих шагах можно наблюдать:
Репозиторий извлечён.
Сообщение выводится в журнал рабочего процесса при выполнении вручную.
Шаг, определенный как
dotnet-code-metrics:-
uses: dotnet/samples/github-actions/DotNet.GitHubAction@main— это расположение контейнерного приложения .NET в этом руководстве. -
envсоздает переменную среды"GREETING", которая выводится при выполнении приложения. -
withуказывает каждый из обязательных входных данных действия.
-
Условный шаг с именем
Create pull requestвыполняется, когда шагdotnet-code-metricsуказывает выходной параметрupdated-metricsзначениемtrue.
Это важно
GitHub позволяет создавать зашифрованные секреты. Секреты можно использовать в составе рабочего процесса с помощью синтаксиса ${{ secrets.SECRET_NAME }} . В контексте действия GitHub существует маркер GitHub, который автоматически заполняется по умолчанию: ${{ secrets.GITHUB_TOKEN }} Дополнительные сведения см. в синтаксисе контекста и выражений для GitHub Actions.
Соберите всё вместе
Репозиторий dotnet/samples GitHub является домом для многих проектов исходного кода .NET, включая приложение в этом руководстве.
Созданный файл CODE_METRICS.md доступен для навигации. Этот файл представляет иерархию проанализированных проектов. Каждый проект содержит верхнеуровневый раздел и эмодзи, который отражает общее состояние наиболее высокой цикломатической сложности для вложенных объектов. При переходе по файлу каждый раздел предоставляет возможности детализации с сводкой по каждой области. В Markdown включены сворачиваемые разделы для дополнительного удобства.
Иерархия развивается начиная с:
- Файл проекта для сборки
- Сборка для пространства имен
- Пространство имен для именованного типа
- Каждый именованный тип имеет таблицу, и каждая таблица имеет:
- Ссылки на номера строк для полей, методов и свойств
- Отдельные оценки для метрик кода
В действии
Рабочий процесс указывает, что при внесении изменений в ветку main, запускается действие. При запуске вкладка "Действия" в GitHub отображает поток текущего журнала выполнения. Ниже приведен пример журнала из .NET code metrics запуска:
Улучшения производительности
Если вы следовали примеру, возможно, вы заметили, что при каждом использовании этого действия будет выполняться docker build для этого образа. Таким образом, каждому триггеру требуется некоторое время, чтобы создать контейнер перед запуском. Перед выпуском GitHub Actions в Marketplace необходимо:
- (автоматически) Создание образа Docker
- Отправьте образ Docker в реестр контейнеров GitHub (или любой другой общедоступный реестр контейнеров)
- Измените действие, чтобы не создать образ, а использовать образ из общедоступного реестра.
# 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!!
Дополнительные сведения см. в документации GitHub: работа с реестром контейнеров.
См. также
- универсальный хост .NET
- Внедрение зависимостей в .NET
- Значения метрик кода
- GitHub Action с открытым исходным кодом, разработанная на .NET, с рабочим процессом для создания и автоматической публикации образа Docker.