استفاده از GitHub Actions برای Build و توزیع خودکار پروژه‌های NET Core.
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: چهار دقیقه

پیشتر مطلب « تولید و ارسال خودکار بسته‌های NuGet پروژه‌های NET Core. به کمک AppVeyor » را در این سایت مطالعه کرده‌اید. اخیرا GitHub نیز دقیقا همین امکانات یکپارچگی مداوم یا Continuous Integration را تحت عنوان GitHub Action، به مخازن کد خود اضافه کرده‌است. البته این قابلیت هنوز در مرحله‌ی بتا است و برای فعالسازی آن بر روی مخازن کد خود نیاز است در اینجا ثبت نام کنید. بعد از یکی دو روز صبر کردن، این برگه‌ی جدید، به مخازن کد شما اضافه خواهد شد:



فعالسازی GitHub Action مخصوص NET Core.

در ادامه قصد داریم از این قابلیت جدید، جهت Build خودکار پروژه‌های NET Core. و در آخر ارسال خودکار بسته‌های نیوگت متناظر آن‌ها به سایت nuget.org، استفاده کنیم. برای این منظور به برگه‌ی Actions مخزن کد خود مراجعه کنید (تصویر فوق). سپس در این صفحه، بر روی لینک Work flows for … more کلیک کنید:


تا امکان انتخاب گردش کاری متناظر با NET Core. ظاهر شود:


در اینجا بر روی دکمه‌ی «Set up this workflow» کلیک کنید تا صفحه‌ی ویرایشی این گردش کاری که با فرمت yml است، ظاهر شود.


 محتویات آن‌‌را برای نمونه می‌توانید به صورت زیر تغییر دهید:
name: .NET Core Build

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v1
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.0.100-preview9-014004        
    - name: Build DNTCaptcha.Core lib
      run: dotnet build ./src/DNTCaptcha.Core/DNTCaptcha.Core.csproj --configuration Release
در این گردش کاری، ابتدا SDK با شماره 3.0.100-preview9-014004 به صورت خودکار نصب خواهد شد. سپس دستور dotnet build بر روی یک فایل csproj خاص، اجرا می‌گردد. اگر نتیجه‌ی این Build موفقیت آمیز بود، یک علامت چک‌مارک سبز رنگ ظاهر می‌شود و در غیر اینصورت یک ایمیل شکست عملیات را نیز دریافت خواهید کرد.
پس از تکمیل محتوای فایل yml در این مرحله، در کنار صفحه بر روی لینک start commit کلیک کنید، تا این فایل را به صورت خودکار در مسیر github\workflows\aspnetcore.yml ذخیره کند. بدیهی است تغییرات آن‌را در قسمت commits مخزن کد نیز می‌توانید مشاهده کنید.


این فایل on: [push] کار می‌کند. یعنی اگر تغییری را به مخزن کد اعمال کردید، همانند یک تریگر عمل کرده و عملیات Build را به صورت خودکار آغاز می‌کند.



اضافه کردن نماد گردش کاری GitHub به پروژه

هر گردش کاری تعریف شده را می‌توان با یک نماد یا badge در فایل readme.md پروژه نیز نمایش داد:


فرمول آن نیز به صورت زیر است:
https://github.com/<OWNER>/<REPOSITORY>/workflows/<WORKFLOW_NAME>/badge.svg
یک مثال:
 ![Github tags](https://github.com/VahidN/DNTCaptcha.Core/workflows/.NET%20Core%20Build/badge.svg)
در اینجا نام گردش کاری، همان نامی است که داخل فایل yml درج شده‌است و نه نام فایل متناظر. بدیهی است این نام را باید به صورت encoded وارد کنید. برای مثال اگر دارای فاصله است، نیاز است 20%‌های فواصل را به این نام اضافه کنید تا URL نهایی درست کار کند.


تکمیل گردش کاری Build، جهت تولید خودکار و ارسال یک بسته‌ی نیوگت

برای ارسال خودکار حاصل Build به سایت نیوگت، نیاز است یک API Key داشته باشیم. به همین جهت به صفحه‌ی مخصوص آن در سایت nuget پس از ورود به سایت آن، مراجعه کرده و یک کلید API جدید را صرفا برای این پروژه تولید کنید (در قسمت Available Packages بسته‌ی پیشینی را که دستی آپلود کرده بودید انتخاب کنید).


پس از کپی کردن کلید تولید شده‌ی در سایت nuget:


به قسمت settings -> secrets مخزن کد خود مراجعه کرده و این کلید را به صورت زیر وارد کنید:


در ادامه برای دسترسی به این کلید با نام NUGET_API_KEY، می‌توان از روش {{ secrets.NUGET_API_KEY }}$ در اسکریپت گردش کاری استفاده کرد.

اکنون که مخزن کد به همراه کلید API نیوگت است، می‌توان مراحل dotnet pack (برای تولید فایل nupkg) و سپس dotnet nuget push (برای انتشار خودکار فایل nupkg) را به صورت زیر، به گردش کاری خود اضافه نمود:
name: .NET Core Build

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v1
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.0.100-preview9-014004        
    - name: Build DNTCaptcha.Core lib
      run: dotnet build ./src/DNTCaptcha.Core/DNTCaptcha.Core.csproj --configuration Release
    - name: Build NuGet Package
      run: dotnet pack ./src/DNTCaptcha.Core/DNTCaptcha.Core.csproj --configuration Release
    - name: Deploy NuGet Package
      run: dotnet nuget push ./src/DNTCaptcha.Core/bin/Release/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json
ویرایش یک گردش کاری، همانند ویرایش یک فایل متنی معمولی مخزن کد است. می‌توان آن‌را به صورت محلی در مسیر github\workflows\aspnetcore.yml. ویرایش کرد و سپس commit، تا سبب به روز رسانی گردش کاری پروژه شود.
  • #
    ‫۵ سال قبل، پنجشنبه ۲۱ شهریور ۱۳۹۸، ساعت ۱۵:۵۵
    چند نکته‌ی تکمیلی:
    - مخزن کد action نصب دات نت Core در اینجا است: « setup-dotnet »
    - دستور ارسال nupkgها اگر به نمونه‌ی موجودی برخورد کند، با خطای 409 متوقف می‌شود (یعنی اگر سعی در ارسال مجدد یک nupkg به علت تغییری خاص، صورت گیرد). به همین جهت کل Build را به صورت شکست خورده معرفی می‌کند. قرار است پرچم skip-duplicate-- پس از ارائه‌ی نهایی NET Core 3.0. به دستور dotnet nuget push اضافه شود. به همین جهت فعلا اگر می‌خواهید نماد صفحه‌ی اول، پیام شکست خوردن را نمایش ندهد، دو work flow را ایجاد کنید؛ یکی برای build و یکی برای ارسال به نیوگت.
    - نماد را به این صورت هم می‌توان نمایش داد:
    <p align="left">  
      <a href="https://github.com/actions/setup-java">
         <img alt="GitHub Actions status" src="https://github.com/actions/setup-java/workflows/Main%20workflow/badge.svg">
      </a>
    </p>
  • #
    ‫۵ سال قبل، شنبه ۲۳ شهریور ۱۳۹۸، ساعت ۲۱:۲۹
    سلام فقط امکان استفاده از دات نت کور هستش؟ نمیشه برای برنامه‌های دات نت فریمورک هم استفاده کنیم؟
    • #
      ‫۵ سال قبل، یکشنبه ۲۴ شهریور ۱۳۹۸، ساعت ۰۰:۵۴
      یکی از پیشنیازهای کار با سیستم‌های DevOps، دسترسی به یک CLI پیشرفته‌است. CLI مربوط به NET Full. برای کامپایل یک پروژه، چنین شکلی را دارد (و من بعید می‌دانم که 99 درصد توسعه دهندگان دانت، حتی یکبار از آن به صورت مستقیم استفاده کرده باشند). ایرادی هم به آن وارد نیست؛ چون طراحی اصلی آن به حدود سال‌های 2000 میلادی بر می‌گردد. اما برای NET Core. وضع فرق می‌کند. CLI پیشرفته‌ی آن هست که از ایجاد پروژه تا افزودن ارجاعات، ساخت و اجرا را به سادگی مدیریت می‌کند و همچنین چندسکویی است و سازگاری کاملی را با سیستم‌های DevOps جدید دارد. یک چنین CLI ایی برای Full .NET Framework وجود ندارد و در حد batch نویسی برای csc.exe است؛ چون ویژوال استودیو تا به امروز تمام پیچیدگی‌های آن‌را مدیریت کرده و نیازی به این CLI نبوده. اما در سایر سکوهای کاری این CLI هست که مدیریت تمام امور را انجام می‌دهد. حتی اگر بحث انتقال پروژه‌های WinForms و یا WPF به NET Core 3.0. مطرح هست، باز هم یکی از مهم‌ترین دلایل آن دسترسی به همین سیستم Build پیشرفته‌است. 
  • #
    ‫۴ سال و ۱۱ ماه قبل، یکشنبه ۱۴ مهر ۱۳۹۸، ساعت ۱۲:۱۷
    یک نکته‌ی تکمیلی: چگونه از چندین سیستم عامل برای اجرای ساخت و آزمایش برنامه استفاده کنیم؟
    name: ASP.NET Core CI
    
    on: [push]
    
    jobs:
      build_and_test:
        runs-on: $
        strategy:
          matrix:
            os: [macOS-latest, ubuntu-latest, windows-latest]
        steps:
        - name: Setup .NET Core
          uses: actions/setup-dotnet@v1.2.0
          with:
            dotnet-version: 3.0.100
          if: matrix.os == 'macOS-latest' || matrix.os == 'ubuntu-latest'
        - uses: actions/checkout@v1
        - name: Build with dotnet
          run: dotnet build ./src/Solution.sln --configuration Release
        - name: Test with dotnet
          run: dotnet test ./src/Solution.sln --configuration Release
    matrix.os امکان تعریف چندین سیستم عامل را میسر می‌کند و سپس در قسمت if نوشته شده، بر اساس نوع سیستم عامل، NET Core. را نصب خواهد کرد؛ چون نگارش ویندوزی آن‌را به همراه دارد.
  • #
    ‫۴ سال و ۵ ماه قبل، دوشنبه ۱۱ فروردین ۱۳۹۹، ساعت ۰۴:۱۵
    یک نکته تکمیلی :
    کد زیر یک کد نسبتا کامل برای Workflow کتابخانه‌های NET Core. است
    • از اجرای workflow اضافی به هنگام تغییر فایل readme.md جلوگیری میکند (می توانید فایل یا پوشه‌های دیگری را هم اضافه کنید)
    • مراحل Build و Test پروژه را در حالت Release انجام میدهد
    • فایل .nupkg مورد نیاز برای پکیج Nuget را در حالت Release ایجاد میکند (عبارت src نام پوشه اصلی پروژه است; در صورت نیاز تغییر دهید)
    • به هنگام Push شدن ریپازیتوری به همراه تگ "release " به صورت خودکار پکیج را به سایت nuget آپلود میکند (عبارت secrets.NUGET_TOKEN شامل مقدار API_KEY شما در سایت Nuget است که باید در قسمت Setting ریپازیتوری، قسمت Secrects ذخیره شده باشد)
    name: .NET Core
    
    on:
      push:
        paths-ignore:
          - 'readme.md'
      pull_request:
        paths-ignore:
          - 'readme.md'
    
    jobs:
      build:
        runs-on: ubuntu-latest
    
        steps:
        - name: Checkout
          uses: actions/checkout@v2
    
        - name: Setup .NET Core
          uses: actions/setup-dotnet@v1
          with:
            dotnet-version: 3.1.101
    
        - name: Build (Release)
          run: dotnet build --configuration Release
    
        - name: Test (Release)
          run: dotnet test --configuration Release
    
        - name: Pack (Release)
          run: dotnet pack src --configuration Release
    
        - name: Publish (Nuget)
          if: github.event_name == 'push'
          run: |      
              if ( "${{github.ref}}" -match "^refs/tags/[0-9]+\.[0-9]+\.[0-9]+$" ) {
                  dotnet nuget push src\bin\Release\*.nupkg -s nuget.org -k ${{secrets.NUGET_TOKEN}}
              } else {
                  echo "Publish is only enabled by tagging with a release tag."
              }

  • #
    ‫۴ سال و ۵ ماه قبل، دوشنبه ۱۱ فروردین ۱۳۹۹، ساعت ۱۰:۰۸
    یک نکته تکمیلی :
    به هنگام تغییر فایل .yaml مربوط به github actions از روی local (و نه خود github) و push کردن آن به گیتهاب ممکن است به خطای زیر برخورد کنید.
    refusing to allow an OAuth App to create or update workflow `.github/workflows/dotnetcore.yml` without `workflow` scope
    این باگ قبلا اینجا گزارش شده است و راه حل آن نیز اینجا و اینجا ارائه شده است.
    راه حل این است که Credential Manager ویندوز رفته و گزینه مربوط به "git:https://github.com" را حذف کنید. بدین ترتیب زمانی که دوباره دستور git push را اجرا میکنید از شما مجددا Crediential را درخواست میکند و بعد از آن می‌توانید بدون مشکل فایل .yaml را هل بدهید [ push کنید (-; ]
  • #
    ‫۴ سال و ۵ ماه قبل، سه‌شنبه ۱۲ فروردین ۱۳۹۹، ساعت ۲۱:۴۰
    یک نکته تکمیلی:
    بعد از Build کردن ریپازیتوری یا Pack کردن پکیج خود می‌توانید فایل‌های تولید شده را در جایی به نام "Artifacts" ذخیره کنید تا در زمان دلخواه بتوانید آنها را دانلود کنید
    به جهت انجام این کار باید از اکشن upload-artifact استفاده کنید. مثال:
    name: Build
    on: [push]
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
        - name: Checkout
          uses: actions/checkout@v2
        - name: Setup .NET Core
          uses: actions/setup-dotnet@v1
        - name: Build (Release)
          run: dotnet build src --configuration Release
        - name: Pack (Release)
          run: dotnet pack src --configuration Release
    
        - name: Upload Artifact
          uses: actions/upload-artifact@v1.0.0
          with:
            name: Release_Artifacts
            path: src\bin\Release
    • عبارت src به پوشه پروژه اصلی اشاره میکند. (در صورت نیاز آن را تغییر دهید)
    • عبارت "Release_Artifacts" نام فایل Artifacts خروجی شماست که با این نام ذخیره می‌شود.
    • مسیر "src\bin\Release" پوشه ای است که میخواهید محتوای آن را در Artifacts ذخیره کنید.
    بعد از اتمام فرایند در صورت موفقیت آمیز بودن فرایند، فایل Artifacts را میتوانید از این قسمت دانلود کنید. 

  • #
    ‫۴ سال و ۵ ماه قبل، سه‌شنبه ۱۲ فروردین ۱۳۹۹، ساعت ۲۲:۲۵
    یک نکته تکمیلی تر:
    اگر بخواهید پروژه خود را توسط چندین تارگت NET Core. ایی Build کنید در حالت عادی امکان پذیر نیست. این محدودیت اینجا گزارش شده است و راه حل (workaround) آن نیز اینجا ارائه شده است.
    در مورد پشتیبانی از چندین target (توسط خاصیت TargetFrameworks در فایل csproj.) قبلا اینجا توضیح داده شده است. تنها نکته این کد این است که برای تارگت هایی که توسط NET Core. بیلد میشوند کار میکند و نه تارگت‌های NET Framework Full.
    با فرض اینکه مثلا target پروژه بر روی netcoreapp2.1 و  netcoreapp3.0  تنظیم شده است و یا هر target دیگری که توسط NET Core. قابل  Build شدن است (مثلا  netstandard2.0 و  netstandard2.1) مثال آن به نحو زیر خواهد بود.
    name: Build
    on: [push]
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
        - name: Checkout
          uses: actions/checkout@v2
    
        - name: Setup .NET Core 2.1
          uses: actions/setup-dotnet@v1
          with:
            dotnet-version: 2.1.607
    
        - name: Setup .NET Core 3.0
          uses: actions/setup-dotnet@v1
          with:
            dotnet-version: 3.0.101
    
        - name: .NET Core SxS
          run: |
            rsync -a ${DOTNET_ROOT/3.0.101/2.1.607}/* $DOTNET_ROOT/
    
        - name: Build (Release - netcoreapp2.1)
          run: dotnet build --configuration Release --framework netcoreapp2.1
    
        - name: Build (Release - netcoreapp3.0)
          run: dotnet build --configuration Release --framework netcoreapp3.0  
    • NET Core. نسخه‌های 2.1.607 و 3.0.101 در دو step نصب شده اند.
    • سپس sync کردن این دو توسط دستور rsync انجام شده است.
    • توسط تنظیم --framework به مقادیر netcoreapp2.1 و netcoreapp3.0 ، عملیات build توسط این دو target انجام شده است.
  • #
    ‫۴ سال و ۵ ماه قبل، سه‌شنبه ۱۲ فروردین ۱۳۹۹، ساعت ۲۲:۴۹
    یک نکته تکمیلی دیگر:
    توسط کد زیر میتوانید اطلاعاتی از محیط اجرا شدن Github Action مورد نظر جمع آوری و لاگ کنید
     از جمله :
    •  event اجرا شده (مثلا push) و شخص فراخوان این رخداد
    • جزئیات commit ایی که منجر به این event شده از جمله SHA hash کامیت، author و committer کامیت
    • تعداد Issue ها، Fork‌ها و Star‌های ریپازیتوری در آن لحظه
    • و بسیاری اطلاعات دیگر
        steps:
        - name: Dump GitHub Context
          env:
            GITHUB_CONTEXT: ${{ toJson(github) }}
          run: echo "$GITHUB_CONTEXT"
    نمونه خروجی تولید شده
    GITHUB_CONTEXT: {
      "token": "***",
      "ref": "refs/heads/master",
      "sha": "3251394ad66ae8419e606fbf78570906ff2f01d3",
      "repository": "mjebrahimi/github_actions_test",
      "repositoryUrl": "git://github.com/mjebrahimi/github_actions_test.git",
      "run_id": "66966756",
      "run_number": "17",
      "actor": "mjebrahimi",
      "workflow": ".NET Core",
      "head_ref": "",
      "base_ref": "",
      "event_name": "push",
      "event": {
        "after": "3251394ad66ae8419e606fbf78570906ff2f01d3",
        "base_ref": null,
        "before": "b6c382e8fe74916daf6821a5a71efe480bd98a13",
        "commits": [
          {
            "author": {
              "email": "mj.ebrahimi72@gmail.com",
              "name": "Mohammad Javad Ebrahimi",
              "username": "mjebrahimi"
            },
            "committer": {
              "email": "noreply@github.com",
              "name": "GitHub",
              "username": "web-flow"
            },
            "distinct": true,
            "id": "3251394ad66ae8419e606fbf78570906ff2f01d3",
            "message": "Update dotnetcore.yml",
            "timestamp": "2020-03-31T04:48:53+04:30",
            "tree_id": "e27a05129010b3b2a7b18b92d91cd73a32babb8f",
            "url": "https://github.com/mjebrahimi/github_actions_test/commit/3251394ad66ae8419e606fbf78570906ff2f01d3"
          }
        ],
        "compare": "https://github.com/mjebrahimi/github_actions_test/compare/b6c382e8fe74...3251394ad66a",
        "created": false,
        "deleted": false,
        "forced": false,
        "head_commit": {
          "author": {
            "email": "mj.ebrahimi72@gmail.com",
            "name": "Mohammad Javad Ebrahimi",
            "username": "mjebrahimi"
          },
          "committer": {
            "email": "noreply@github.com",
            "name": "GitHub",
            "username": "web-flow"
          },
          "distinct": true,
          "id": "3251394ad66ae8419e606fbf78570906ff2f01d3",
          "message": "Update dotnetcore.yml",
          "timestamp": "2020-03-31T04:48:53+04:30",
          "tree_id": "e27a05129010b3b2a7b18b92d91cd73a32babb8f",
          "url": "https://github.com/mjebrahimi/github_actions_test/commit/3251394ad66ae8419e606fbf78570906ff2f01d3"
        },
        "pusher": {
          "email": "mj.ebrahimi72@gmail.com",
          "name": "mjebrahimi"
        },
        "ref": "refs/heads/master",
        "repository": {
          "archive_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/{archive_format}{/ref}",
          "archived": false,
          "assignees_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/assignees{/user}",
          "blobs_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/git/blobs{/sha}",
          "branches_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/branches{/branch}",
          "clone_url": "https://github.com/mjebrahimi/github_actions_test.git",
          "collaborators_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/collaborators{/collaborator}",
          "comments_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/comments{/number}",
          "commits_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/commits{/sha}",
          "compare_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/compare/{base}...{head}",
          "contents_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/contents/{+path}",
          "contributors_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/contributors",
          "created_at": 1585584602,
          "default_branch": "master",
          "deployments_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/deployments",
          "description": null,
          "disabled": false,
          "downloads_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/downloads",
          "events_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/events",
          "fork": false,
          "forks": 0,
          "forks_count": 0,
          "forks_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/forks",
          "full_name": "mjebrahimi/github_actions_test",
          "git_commits_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/git/commits{/sha}",
          "git_refs_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/git/refs{/sha}",
          "git_tags_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/git/tags{/sha}",
          "git_url": "git://github.com/mjebrahimi/github_actions_test.git",
          "has_downloads": true,
          "has_issues": true,
          "has_pages": false,
          "has_projects": true,
          "has_wiki": true,
          "homepage": null,
          "hooks_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/hooks",
          "html_url": "https://github.com/mjebrahimi/github_actions_test",
          "id": 251358686,
          "issue_comment_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/issues/comments{/number}",
          "issue_events_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/issues/events{/number}",
          "issues_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/issues{/number}",
          "keys_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/keys{/key_id}",
          "labels_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/labels{/name}",
          "language": "C#",
          "languages_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/languages",
          "license": null,
          "master_branch": "master",
          "merges_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/merges",
          "milestones_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/milestones{/number}",
          "mirror_url": null,
          "name": "github_actions_test",
          "node_id": "MDEwOlJlcG9zaXRvcnkyNTEzNTg2ODY=",
          "notifications_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/notifications{?since,all,participating}",
          "open_issues": 0,
          "open_issues_count": 0,
          "owner": {
            "avatar_url": "https://avatars1.githubusercontent.com/u/23256135?v=4",
            "email": "mj.ebrahimi72@gmail.com",
            "events_url": "https://api.github.com/users/mjebrahimi/events{/privacy}",
            "followers_url": "https://api.github.com/users/mjebrahimi/followers",
            "following_url": "https://api.github.com/users/mjebrahimi/following{/other_user}",
            "gists_url": "https://api.github.com/users/mjebrahimi/gists{/gist_id}",
            "gravatar_id": "",
            "html_url": "https://github.com/mjebrahimi",
            "id": 23256135,
            "login": "mjebrahimi",
            "name": "mjebrahimi",
            "node_id": "MDQ6VXNlcjIzMjU2MTM1",
            "organizations_url": "https://api.github.com/users/mjebrahimi/orgs",
            "received_events_url": "https://api.github.com/users/mjebrahimi/received_events",
            "repos_url": "https://api.github.com/users/mjebrahimi/repos",
            "site_admin": false,
            "starred_url": "https://api.github.com/users/mjebrahimi/starred{/owner}{/repo}",
            "subscriptions_url": "https://api.github.com/users/mjebrahimi/subscriptions",
            "type": "User",
            "url": "https://api.github.com/users/mjebrahimi"
          },
          "private": false,
          "pulls_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/pulls{/number}",
          "pushed_at": 1585613933,
          "releases_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/releases{/id}",
          "size": 40,
          "ssh_url": "git@github.com:mjebrahimi/github_actions_test.git",
          "stargazers": 0,
          "stargazers_count": 0,
          "stargazers_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/stargazers",
          "statuses_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/statuses/{sha}",
          "subscribers_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/subscribers",
          "subscription_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/subscription",
          "svn_url": "https://github.com/mjebrahimi/github_actions_test",
          "tags_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/tags",
          "teams_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/teams",
          "trees_url": "https://api.github.com/repos/mjebrahimi/github_actions_test/git/trees{/sha}",
          "updated_at": "2020-03-31T00:01:15Z",
          "url": "https://github.com/mjebrahimi/github_actions_test",
          "watchers": 0,
          "watchers_count": 0
        },
        "sender": {
          "avatar_url": "https://avatars1.githubusercontent.com/u/23256135?v=4",
          "events_url": "https://api.github.com/users/mjebrahimi/events{/privacy}",
          "followers_url": "https://api.github.com/users/mjebrahimi/followers",
          "following_url": "https://api.github.com/users/mjebrahimi/following{/other_user}",
          "gists_url": "https://api.github.com/users/mjebrahimi/gists{/gist_id}",
          "gravatar_id": "",
          "html_url": "https://github.com/mjebrahimi",
          "id": 23256135,
          "login": "mjebrahimi",
          "node_id": "MDQ6VXNlcjIzMjU2MTM1",
          "organizations_url": "https://api.github.com/users/mjebrahimi/orgs",
          "received_events_url": "https://api.github.com/users/mjebrahimi/received_events",
          "repos_url": "https://api.github.com/users/mjebrahimi/repos",
          "site_admin": false,
          "starred_url": "https://api.github.com/users/mjebrahimi/starred{/owner}{/repo}",
          "subscriptions_url": "https://api.github.com/users/mjebrahimi/subscriptions",
          "type": "User",
          "url": "https://api.github.com/users/mjebrahimi"
        }
      },
      "workspace": "/home/runner/work/github_actions_test/github_actions_test",
      "action": "run1"
    }

    با توجه به این نکته، اگر میخواین توی یه کامیت، عملیات CI رو به هر دلیلی Skip/Ignore کنین میتونین اینطوری عمل کنین.
    jobs:
      build:
        if: contains(toJson(github.event.commits), '[SKIP CI]') == false
        runs-on: ubuntu-latest
    ...
    در این صورت هر کامیت ایی که توی message اش، عبارت "[SKIP CI]" باشه Workflow روش اجرا نمیشه .  
  • #
    ‫۴ سال و ۵ ماه قبل، چهارشنبه ۱۳ فروردین ۱۳۹۹، ساعت ۰۵:۲۱
    یک نکته تکمیلی:
    برای Build پروژه‌های NET Framework Full. (مانند پروژه‌های ASP.NET MVC قدیم) باید به شکل زیر عمل کنید.
    jobs:
      build:
    
        runs-on: windows-latest
        
        steps:
        - name: Checkout
          uses: actions/checkout@v2
            
        - name: Setup MSBuild
          uses: microsoft/setup-msbuild@v1.0.0  
           
        - name: Setup NuGet
          uses: nuget/setup-nuget@v1.0.2
         
        - name: Restore NuGet Packages
          run: nuget restore src/WebApplication1.sln
     
        - name: Build (Release)
          run: msbuild src/WebApplication1.sln /p:Configuration=Release
    • دستور runs-on: windows-latest این workflow را بر روی ویندوز اجرا میکنه (بدیهیه که پروژه‌های دات نت Full بر روی غیر از ویندوز قابل build شدن نیست)
    • در step دوم MSBuild رو توسط اکشن microsoft/setup-msbuild نصب میکنیم.
    • در step سوم Nuget رو توسطاکشن nuget/setup-nuget نصب میکنیم.
    • در step چهارم وابستگی (پکیج)‌های پروژه رو restore میکنیم. 
    • در step چهارم پروژه رو توسط msbuild و در مود Release بیلد میکنیم.
    • عبارت src/WebApplication1.sln به پوشه و نام فایل سلوشن شما اشاره میکنه.

    و برای Test پروژه‌های خود میتونین از اکشن  Malcolmnixon/Setup-VSTest به نحو زیر استفاده کنین
        - name: Setup VSTest
          uses: Malcolmnixon/Setup-VSTest@v2
    
        - name: VSTest
          run: vstest.console ClassLibrary.Test\bin\Debug\ClassLibrary.Test.dll
    عبارت ClassLibrary.Test\bin\Debug\ClassLibrary.Test.dll   به مسیر و نام dll تست شما اشاره میکنه.
  • #
    ‫۴ سال و ۵ ماه قبل، پنجشنبه ۱۴ فروردین ۱۳۹۹، ساعت ۰۲:۰۶
    یک نکته تکمیلی:
    اگه در workflow خود توسط دستور dotnet nuget push   اقدام به پابلیش پکیج خود کردید و با خطای زیر مواجه شدید (که منجر به fail شدن workflow شما در github خواهد شد)
    error: File does not exist (src\bin\Release\*.snupkg).
    راه حل آن افزودن کد‌های زیر به فایل csproj. پروژه است
    <PropertyGroup>
       ...
       <DebugSymbols>true</DebugSymbols>
       <IncludeSymbols>true</IncludeSymbols>
       <SymbolPackageFormat>snupkg</SymbolPackageFormat>
    </PropertyGroup>
    این دستور باعث میشه فایلی با پسوند snupkg. در که شامل symbol‌های پکیج شماست ساخته شود و در نتیجه خطای مذکور برطرف و عملیات workflow با موفقیت انجام شود.
  • #
    ‫۱ سال و ۶ ماه قبل، شنبه ۱۵ بهمن ۱۴۰۱، ساعت ۱۹:۱۰
    چند نکته‌ی تکمیلی:
    - بجای دستور dotnet pack در گردش کاری‌های فوق، می‌توان تنظیم زیر را به فایل csproj. برنامه اضافه کرد:
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>

    - اگر قصد build یک پروژه‌ی library مخصوص دات نت 4x و دات نت جدید را با هم و توسط دستور dotnet build دارید، یعنی این پروژه multi-target است:
    <TargetFrameworks>netstandard2.0;net462;</TargetFrameworks>
    فقط کافی است قسمت تنظیم سیستم عامل را به صورت زیر تغییر دهید؛ چون ویندوز 2019 به همراه SDK مخصوص build دات نت 4x هم هست:
    runs-on: windows-2019