کاربرد Action ها در Github - خودکار سازی فرآیند کامپایل و آپلود فایل در Release گیت‌هاب
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: هفت دقیقه

نکته: این آموزش مبتنی بر دات نت نسخه 5 می‌باشد (قابل استفاده در نسخه 3.0 و 3.1 نیز می‌باشد اما تست نشده است). در این آموزش فرض شده‌است که شما توانایی کار کردن با git و گیت‌هاب را دارید. همچنین دقت کنید که گزینه‌های زیر در فایل csproj شما موجود باشد، در غیر این صورت ممکن است با خطا مواجه شوید:
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<PublishSingleFile>true</PublishSingleFile>

چند وقتی می‌شود که گیت‌هاب اکشن‌ها را معرفی کرده که با استفاده از این اکشن‌ها میتوان برخی فعالیت‌های تکراری را، خودکار سازی کرد و در وقت و انرژی صرفه جویی کرد. ما چه کارهایی را میتوانیم با کمک اکشن‌ها انجام بدهیم؟ تقریبا میشود گفت هرکاری را میتوان با اکشن‌ها انجام داد. کامپایل کردن پروژه، تست کردن، پابلیش کردن و...
من معمولا فایل‌های خروجی که برای پروژه‌هایم میگیرم، بدلیل استفاده از ویژگی SelfContained و ایمیج‌های ReadyToRun برای اجرای سریعتر، معمولا حجمی حدود 140 مگ دارند. حالا وقتی آنها را فشرده میکنم، به حدود 50 مگ کاهش پیدا میکنند که اگر من بخواهم هر دفعه که از برنامه خروجی میگیرم، فایل خروجی را فشرده کنم و آن را در گیت‌هاب آپلود کنم، هم فرآیندی زمانبر هست و هم اینکه تکراری و خسته کننده؛ در نتیجه تصمیم گرفتم که از اکشن گیت‌هاب برای خودکارسازی این فرآیند استفاده کنم. 
در این نوشته میخواهیم یک اکشن بنویسیم که بر اساس سورس کد موجود بر روی گیت‌هاب، برنامه را کامپایل کند، فایل اجرایی را بصورت فایل فشرده Zip ایجاد کرده و در نهایت این فایل فشرده را در قسمت Release گیت‌هاب منتشر کند.
برای شروع کار اول باید در مخزن پروژه، در سایت گیت‌هاب، به قسمت Action برویم:

حالا روی قسمت New workflow کلیک میکنیم
 
شما میتونید از قالب‌های پیش‌فرض موجود، هر کدام را که خواستید انتخاب کنید. من ترجیح میدهم با یک قالب خالی شروع کنم. پس بر روی set up a workflow yourself کلیک میکنیم:
 
کدهای پیش‌فرضی که وجود دارند را پاک کنید، تا مثل تصویر زیر، یک فایل کاملا تمیز و خالی را داشته باشیم. نکته‌ای که باید دقت کنید، اسم و مسیر فایل می‌باشد. مسیر فایل را اصلا نباید تغییر داد، ولی اسم فایل را میتوانید اصلاح کنید؛ ولی توجه کنید که پسوند فایل باید yml باشد.
حالا نوبت نوشتن کدهای اکشن رسیده:
اول از همه کد زیر را مینویسیم:
name: "Publish"

این خط، اسم اکشن مارا مشخص میکند که قرار است در لیست workflow‌ها نمایش داده شود:
در کد بعدی که باید بنویسیم (در خط بعدی) باید مشخص بکنیم که این اکشن چه زمانی اجرا بشود. گزینه‌های زیر استفاده بیشتری دارند:
  • push = هر زمان که کامیتی روی گیتهاب پوش شود، اکشن اجرا میشود.
  • pull_request = هر زمانی که یک پول ریکوئست مرج شود، اکشن اجرا میشود.
  • workflow_dispatch = برنامه نویس خودش میتواند با کلیک بر روی دکمه‌ی مشخصی در قسمت اکشن‌ها، اکشن موردنظر را اجرا کند.
لیست کامل تریگر‌ها را میتوانید اینجا مطالعه کنید.
ما از push استفاده میکنیم؛ البته مقداری آن را تغییر میدهیم تا زمانیکه شامل تگ بود، اکشن اجرا شود.
on:
  push:
    tags:
      - "v*"
نکته‌ای که وجود دارد، ما در آخر این دستور، از *v استفاده کردیم که اشاره میکند اگر تگی بصورت v1.0.0 بود، اجرا بشود. * میتواند هر عددی باشد.
3 متغیر ایجاد میکنیم تا محل فایل پروژه، اجرایی و فشرده را نگه دارد، تا فایل اکشن زیاد شلوغ نباشد. 
env:
  PROJECT_PATH: src/HandySub/HandySub.csproj
  ZIP_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub-x86.zip
  EXE_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub.exe
حالا باید دستورات خودکار سازی را بنویسیم. همه دستورات باید در قسمت jobs نوشته شوند:
 jobs:
  deploy:
    runs-on: windows-latest
به قسمت runs-on توجه کنید. این گزینه مشخص میکند که اکشن ما بر روی سرور ویندوزی و آخرین نسخه‌ی از آن اجرا بشود؛ در صورت نیاز میتوانید از linux نیز استفاده کنید.
در خط بعدی باید قدم به قدم دستورات را بنویسیم. ما برای هر قدم، از name استفاده میکنیم که هنگام اجرای اکشن، بصورت مرتب و خوانا بتوانیم بفهمیم که در چه مرحله‌ای از اجرا هستیم.
قدم اول باید اکشن را آماده کنیم. اکثر دستورات مهم در این اکشن موجود است:
 steps:
      - name: Initialize Actions
        uses: actions/checkout@v2
قدم بعدی باید sdk دات نت را بر روی سرور، دانلود و نصب کنیم:
     - name: Initialize .Net
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 5.0.x
قبل از بیلد پروژه، باید کتابخانه‌ها و بسته‌های نیوگت را restore کنیم، تا بیلد، خطا نداشته باشد:
  - name: Restore Project
        run: dotnet restore ${{ env.PROJECT_PATH }}
حالا میتوانیم دستور خروجی گرفتن را بنویسیم (حتما باید در فایل csproj پروژه خود، runtimeidentifier  پروژه مشخص باشد که اینجا ما از win-x86 استفاده کردیم؛ در غیر اینصورت خطا میگیرید)  چون در مرحله قبل پروژه را restore کردیم، هنگام خروجی گرفتن، دستور no-restore را مینویسیم تا دوباره بسته‌های نیوگت ری‌استور نشود.
 - name: Publish Project
        run: dotnet publish ${{ env.PROJECT_PATH }} -c Release --self-contained -r win-x86 --no-restore
حالا که فایل اجرایی را ایجاد کردیم، باید آن را بصورت فشرده و zip در بیاوریم. برای اینکار از یک اکشن دیگر کمک میگیریم. اول آن را به اصطلاح using میکنیم؛ سپس از آن استفاده میکنیم. این اکشن 2 ورودی دارد: files و dest که به ترتیب باید آدرس فایل‌ها و محل ذخیره زیپ را به آن بدهیم که ما از متغیرهایی که قبلا ایجاد کرده‌ایم، استفاده میکنیم. 
 - name: Create Zip File
        uses: papeloto/action-zip@v1
        with:
          files: ${{ env.EXE_PATH }}
          dest: ${{ env.ZIP_PATH }}
در مرحله بعدی باید از یک اکشن دیگر برای ساخت Release در قسمت گیت‌هاب کمک بگیریم. دقت کنید که برای آپلود کردن فایل زیپ داخل این Release، ما باید توکن و id این ریلیز را ذخیره کنیم که در اینجا در متغیر GITHUB_TOKEN و id ذخیره میکنیم. توکن را میتوانیم از قسمت secrets خود گیت‌هاب دریافت کنیم. همچنین ما اسم تگ را از طریق github.ref دریافت میکنیم (که مقدار v1.0.0 را به عنوان مثال برای ما برگشت خواهد داد (شماره نسخه همان تگی است که پوش کرده‌ایم) 
 - name: Initialize Release
        uses: actions/create-release@v1
        id: create_release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
حالا نوبت این است که فایل زیپ را آپلود کنیم. دوباره باید از اکشن دیگری برای این امر کمک بگیریم. توکنی را که قبلا ذخیره کردیم، همراه با فایل زیپ، به این اکشن میدهیم و در پایان به کمک id که قبلا ذخیره کردیم، لینک فایل آپلود شده را از آن دریافت میکنیم.  
 - name: Create Release 
        uses: csexton/release-asset-action@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          file: ${{ env.ZIP_PATH }}
          release-url: ${{ steps.create_release.outputs.upload_url }}
کد کامل را اینجا ببینید: 
name: "Publish"

on:
  push:
    tags:
      - "v*"

env:
  PROJECT_PATH: src/HandySub/HandySub.csproj
  ZIP_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub-x86.zip
  EXE_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub.exe
  

jobs:
  deploy:
    runs-on: windows-latest
    steps:
      - name: Initialize Actions
        uses: actions/checkout@v2

      - name: Initialize .Net
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 5.0.x
      
      - name: Restore Project
        run: dotnet restore ${{ env.PROJECT_PATH }}

      - name: Publish Project
        run: dotnet publish ${{ env.PROJECT_PATH }} -c Release --self-contained -r win-x86 --no-restore

      - name: Create Zip File
        uses: papeloto/action-zip@v1
        with:
          files: ${{ env.EXE_PATH }}
          dest: ${{ env.ZIP_PATH }}
          
      - name: Initialize Release
        uses: actions/create-release@v1
        id: create_release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
      
      - name: Create Release    
        uses: csexton/release-asset-action@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          file: ${{ env.ZIP_PATH }}
          release-url: ${{ steps.create_release.outputs.upload_url }}

در آخر بر روی دکمه سبز رنگ بالا سمت راست start commit کلیک کنید تا تغییرات ثبت شوند.
به پروژه خود برگردید و ترمینال را باز کنید و یک تگ جدید را ایجاد کنید. 
git tag v1.0.0
سپس تگ ایجاد شده را به مخزن گیت‌هاب پوش کنید:
git push origin tag v1.0.0

 به مخزن گیت‌هاب مراجعه کنید تا ببینید که اکشن شما بصورت خودکار اجرا شده و در پایان، یک ریلیز برای شما ایجاد میکند.
 در قسمت ریلیز میتوانید ببینید که ریلیز توسط ربات گیت‌هاب ایجاد شده‌است: