글쓴이 보관물: 낭창

[GitHub Actions] 컨텐츠 NuGet 패키지 생성 및 배포하기

C# 프로젝트 진행 중 다른 웹프로젝트의 결과물을 포함해야 되는 상황에 직면했다. 여러가지 방향을 고민 했지만, 최종적으로 결정된건, 해당 웹프로젝트의 결과물을 NuGet 패키지로 만들어서 GitHub의 NuGet Registry 로 배포하고, 이 패키지를 C# 프로젝트에 포함하는 방식.

우선 웹프로젝트의 GitHub 레파지토리에 .github/workflows 폴더에 actions 스크립트를 추가한다.

앞부분에는 프로젝트에 따라 결과물을 생성할 수 있는 빌드 스크립트를 적당히 추가해주고, 이어서 다음과 같이 NuGet.exe 를 사용한 패키지 생성 및 배포 스크립트를 추가한다.

GitHub 에서 해당 레파지토리의 NuGet Registry에 배포를 할 경우, ApiKey 로 secrets.GITHUB_TOKEN을 사용하면 된다.

...

jobs:
  build:
    steps:

      ...

      # NuGet.exe 설치
      - name : Setup NuGet
        uses: NuGet/setup-nuget@1.0.7
        with:
          nuget-version: latest
 
      # NuGet 패키지 생성
      - name: Create NuGet package
        run: nuget pack

      - name: Upload NuGet package
        run: nuget push *.nupkg -configfile NuGet.config -ApiKey ${{ secrets.GITHUB_TOKEN }} -Source "github" -SkipDuplicate

-SkipDuplicate 옵션을 사용하면, 해당 패키지의 버전이 이미 Registry에 존재하더라도 Actions 스크립트의 실행이 실패하지 않도록 하여 주므로, 평소에는 패키지 배포 때문에 Actions 실행이 실패하지 않으면서도 실제 배포가 필요한 경우에만 패키지 버전을 변경하는 방식으로 배포여부를 제어할 수 있다.

NuGet 패키지를 생성하기 위해서는 루트 폴더에 다음과 같이 .nuspec 파일을 만들어 주어야 한다.

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
	<metadata>
		<id>[Company].[Project].[PackageName]</id>
		<version>1.0.0</version>
		<authors>[Company]</authors>
		<owners>[Company Name]</owners>
		<projectUrl>https://www.company.com</projectUrl>
		<repository type="git" url="https://github.com/[owner]/[repository].git" />
		<description>My Company NuGet Package</description>
		<requireLicenseAcceptance>false</requireLicenseAcceptance>
		<copyright>Copyright (c)2022 My Company corp.</copyright>
		<dependencies></dependencies>
		<contentFiles>
			<files include="any\any\**" buildAction="EmbeddedResource" copyToOutput="true" flatten="false"/>		
		</contentFiles>
	</metadata>

	<files>
		<file src="build\**" target="contentFiles\any\any\WebApplication"/>
	</files>
</package>

<id> 는 다른 패키지와 겹치지 않도록 적당한 규칙으로 부여해주면 되고, <repository> 에서 [owner] 에는 레파지토리 소유자 이름, [Repository]에는 해당 레파지토리 이름을 적어 줘야한다. 즉, 여기서는 Package를 업로드할 github 레파지토리의 URL을 적어주면된다. 나머지 항목들은 상황에 맞처 적당히 적어주면 된다.

<files>에서 패키지에 포함할 파일들을 지정한다. 여기서는 build 폴더 하위의 모든 항목을 패키지 내의 contentFiles\any\any\WebApplication 폴더 하위에 넣도록 지정했다. contentFiles 폴더는 패키지내에 컨텐츠 파일들을 저장하는 경로이고, any/any 는 모든 플랫폼과 버전에 해당하는 파일의 경로다.

여기서 또 중요한 건 <contentFiles> 항목이다. 여기서는 패키지 내의 컨텐츠 파일에 대한 설정을 하는데, 기본적으로 컨텐츠 파일의 경로는 패키지 내의 contentsFiles 폴더 하위다. 즉, 위의 <files> 에서 지정한 파일들이 대상이 되는 것이다.

여기서는 any\any 폴더 하위의 모든 파일과 폴더에 대해 빌드 결과물 폴더로 복사하고(copyToOutput=”true”), 복사할때 폴더 구조를 그대로 유지하도록 (flatten=”false”) 설정했다.

이제 패키지를 업로드할 NuGet Registry 설정을 추가하기 위해 프로젝트 폴더 루트에 NuGet.config 파일을 생성하자.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <packageSources>
        <clear />
        <add key="github" value="https://nuget.pkg.github.com/[owner]/index.json" />
    </packageSources>
</configuration>

여기서 <packageSources> 의 <add> 에서 정의한 key의 값이 앞서 Actions 스크립트에서 nuget push 시 지정한 -Source 옵션의 값이다. .nuspec 파일과는 다르게 여기서는 URL은 nuget.pkg.github.com 으로 하여야 하며, 패키지를 배포하는 registry 의 owner 를 [owner] 에 적어주면되다.

여기서 주의 할 것은, 패키지를 생성하는 레파지토리와 NuGet Registry의 owner 가 일치할 경우에만, nuget push 시에 secrets.GITHUB_TOKEN 을 ApiKey 로 사용할 수 있다는 것이다. 각각의 owner 가 다를 경우에는 권한이 있는 계정의 Peronal Access Token 을 생성하고, 프로젝트의 레파지토리 설정에서 secret으로 추가하는 작업을 해주어야 한다.(이경우는 -ApiKey 옵션이 아니라 -username 과 -password 옵션을 사용하여야 한다)

세 파일을 레파지토리에 추가하고 GitHub 레파지토리로 push 해 주면 해당 프로젝트의 결과물을 NuGet 패키지로 배포할 수 있는 준비가 끝난다.