ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

ืื• ืื™ืš ืœื”ืฉื™ื’ ืชื’ื™ื ื™ืคื™ื ืœืคืจื•ื™ืงื˜ ืฉืœืš ื‘ืขืจื‘ ืื—ื“ ืฉืœ ืงื™ื“ื•ื“ ืงืœ

ื›ื ืจืื” ืฉืœื›ืœ ืžืคืชื— ืฉื™ืฉ ืœื• ืœืคื—ื•ืช ืคืจื•ื™ืงื˜ ื—ื™ื™ืช ืžื—ืžื“ ืื—ื“ ื‘ืฉืœื‘ ืžืกื•ื™ื ื™ืฉ ื’ื™ืจื•ื“ ืœื’ื‘ื™ ืชื’ื™ื ื™ืคื™ื ืขื ืกื˜ื˜ื•ืกื™ื, ื›ื™ืกื•ื™ ืงื•ื“, ื’ืจืกืื•ืช ื—ื‘ื™ืœื” ื‘-nuget... ื•ื”ื’ื™ืจื•ื“ ื”ื–ื” ื”ื•ื‘ื™ืœ ืื•ืชื™ ืœื›ืชื•ื‘ ืืช ื”ืžืืžืจ ื”ื–ื”. ื›ื”ื›ื ื” ืœื›ืชื™ื‘ืชื•, ืงื™ื‘ืœืชื™ ืืช ื”ื™ื•ืคื™ ื”ื–ื” ื‘ืื—ื“ ื”ืคืจื•ื™ืงื˜ื™ื ืฉืœื™:

ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

ืžืืžืจ ื–ื” ื™ื“ืจื™ืš ืื•ืชืš ื“ืจืš ื”ื”ื’ื“ืจื” ื”ื‘ืกื™ืกื™ืช ืฉืœ ืื™ื ื˜ื’ืจืฆื™ื” ื•ืืกืคืงื” โ€‹โ€‹ืžืชืžืฉื›ืช ืขื‘ื•ืจ ืคืจื•ื™ืงื˜ ืกืคืจื™ื™ืช ื›ื™ืชื” .Net Core ื‘-GitLab, ืคืจืกื•ื ืชื™ืขื•ื“ ืœื“ืคื™ GitLab ื•ื“ื—ื™ืคืช ื—ื‘ื™ืœื•ืช ื‘ื ื•ื™ื•ืช ืœืคื™ื“ ืคืจื˜ื™ ื‘-Azure DevOps.

ืงื•ื“ VS ืฉื™ืžืฉ ื›ืกื‘ื™ื‘ืช ื”ืคื™ืชื•ื— ืขื ื”ื”ืจื—ื‘ื” ื–ืจื™ืžืช ืขื‘ื•ื“ื” ืฉืœ GitLab (ืœืื™ืžื•ืช ืงื•ื‘ืฅ ื”ื”ื’ื“ืจื•ืช ื™ืฉื™ืจื•ืช ืžืกื‘ื™ื‘ืช ื”ืคื™ืชื•ื—).

ื”ืงื“ืžื” ืงืฆืจื”

CD - ื–ื” ื›ืฉืจืง ื“ื—ืคืช, ื•ื”ื›ืœ ื›ื‘ืจ ื ืคืœ ืขืœ ื”ืœืงื•ื—?

ืžื” ื–ื” CI / CD ื•ืœืžื” ืืชื” ืฆืจื™ืš ืืช ื–ื” - ืืชื” ื™ื›ื•ืœ ื‘ืงืœื•ืช ืœื—ืคืฉ ื‘ื’ื•ื’ืœ. ืžืฆื ืชื™ืขื•ื“ ืžืœื ืขืœ ื”ื’ื“ืจืช ืฆื™ื ื•ืจื•ืช ื‘-GitLab ื’ื ืงืœ. ื›ืืŸ ืืชืืจ ื‘ืงืฆืจื” ื•ื‘ืžื™ื“ืช ื”ืืคืฉืจ ืœืœื ืคื’ืžื™ื ืืช ืชื”ืœื™ืš ื”ืžืขืจื›ืช ืžืžืขื•ืฃ ื”ืฆื™ืคื•ืจ:

  • ื”ืžืคืชื— ืฉื•ืœื— commit ืœืžืื’ืจ, ื™ื•ืฆืจ ื‘ืงืฉืช ืžื™ื–ื•ื’ ื“ืจืš ื”ืืชืจ, ืื• ื‘ื“ืจืš ืื—ืจืช, ื‘ืžืคื•ืจืฉ ืื• ื‘ืžืจื•ืžื– ืžืชื—ื™ืœ ืืช ื”ืฆื™ื ื•ืจ,
  • ื›ืœ ื”ืžืฉื™ืžื•ืช ื ื‘ื—ืจื•ืช ืžืชื•ืš ื”ืชืฆื•ืจื”, ืฉืชื ืื™ื” ืžืืคืฉืจื™ื ืœื”ืคืขื™ืœ ืื•ืชืŸ ื‘ื”ืงืฉืจ ื”ื ืชื•ืŸ,
  • ื”ืžืฉื™ืžื•ืช ืžืื•ืจื’ื ื•ืช ืœืคื™ ื”ืฉืœื‘ื™ื ืฉืœื”ืŸ,
  • ืฉืœื‘ื™ื ืžื‘ื•ืฆืขื™ื ื‘ืชื•ืจื - ื›ืœื•ืžืจ. ื”ืžืงื‘ื™ืœื” ื›ืœ ื”ืžืฉื™ืžื•ืช ื‘ืฉืœื‘ ื–ื” ื”ื•ืฉืœืžื•,
  • ืื ื”ืฉืœื‘ ื ื›ืฉืœ (ื›ืœื•ืžืจ, ืœืคื—ื•ืช ืื—ืช ืžื”ืžืฉื™ืžื•ืช ืฉืœ ื”ืฉืœื‘ ื ื›ืฉืœืช), ื”ืฆื™ื ื•ืจ ื ืขืฆืจ (ื›ืžืขื˜ ืชืžื™ื“),
  • ืื ื›ืœ ื”ืฉืœื‘ื™ื ื”ื•ืฉืœืžื• ื‘ื”ืฆืœื—ื”, ื”ืฆื™ื ื•ืจ ื ื—ืฉื‘ ื›ืžื•ืฆืœื—.

ืœืคื™ื›ืš, ื™ืฉ ืœื ื•:

  • pipeline - ืื•ืกืฃ ืฉืœ ืžืฉื™ืžื•ืช ืžืื•ืจื’ื ื•ืช ืœืฉืœื‘ื™ื ื‘ื”ื ื ื™ืชืŸ ืœื‘ื ื•ืช, ืœื‘ื“ื•ืง, ื—ื‘ื™ืœื” ืงื•ื“, ืœืคืจื•ืก ื‘ื ื™ื™ื” ืžื•ื’ืžืจืช ืœืฉื™ืจื•ืช ืขื ืŸ ื•ื›ื•',
  • ืฉืœื‘ (ืฉืœื‘) - ื™ื—ื™ื“ืช ืืจื’ื•ืŸ ืฆื™ื ื•ืจ, ืžื›ื™ืœื” ืžืฉื™ืžื” ืื—ืช ื•ืžืขืœื”,
  • ืžืฉื™ืžื” (ืขื‘ื•ื“ื”) ื”ื™ื ื™ื—ื™ื“ืช ืขื‘ื•ื“ื” ื‘ืฆื ืจืช. ื”ื•ื ืžื•ืจื›ื‘ ืžืชืกืจื™ื˜ (ื—ื•ื‘ื”), ืชื ืื™ ื”ืฉืงื”, ื”ื’ื“ืจื•ืช ืœืคืจืกื•ื/ืื—ืกื•ืŸ ื—ืคืฆื™ื ื‘ืžื˜ืžื•ืŸ ื•ืขื•ื“ ื”ืจื‘ื” ื™ื•ืชืจ.

ื‘ื”ืชืื ืœื›ืš, ื”ืžืฉื™ืžื” ื‘ืขืช ื”ื’ื“ืจืช CI/CD ืžืกืชื›ืžืช ื‘ื™ืฆื™ืจืช ืžืขืจืš ืžืฉื™ืžื•ืช ื”ืžื™ื™ืฉืžื•ืช ืืช ื›ืœ ื”ืคืขื•ืœื•ืช ื”ื“ืจื•ืฉื•ืช ืœื‘ื ื™ื™ื”, ื‘ื“ื™ืงื” ื•ืคืจืกื•ื ืฉืœ ืงื•ื“ ื•ื—ืคืฆื™ื.

ืœืคื ื™ ืฉืžืชื—ื™ืœื™ื: ืœืžื”?

  • ืœืžื” Gitlab?

ื›ื™ ื›ืฉื”ื™ื” ืฆื•ืจืš ืœื™ืฆื•ืจ ืžืื’ืจื™ื ืคืจื˜ื™ื™ื ืœืคืจื•ื™ืงื˜ื™ื ืฉืœ ื—ื™ื•ืช ืžื—ืžื“, ื”ื ืงื™ื‘ืœื• ืชืฉืœื•ื ื‘-GitHub, ื•ื”ื™ื™ืชื™ ื—ืžื“ื ื™ืช. ื”ืžืื’ืจื™ื ื”ืคื›ื• ืœื—ื™ื ื, ืื‘ืœ ื‘ื™ื ืชื™ื™ื ื–ื• ืœื ืกื™ื‘ื” ืžืกืคืงืช ื‘ืฉื‘ื™ืœื™ ืœืขื‘ื•ืจ ืœ-GitHub.

  • ืœืžื” ืœื Azure DevOps Pipelines?

ืžื›ื™ื•ื•ืŸ ืฉืฉื ื”ื”ื’ื“ืจื” ื”ื™ื ืืœืžื ื˜ืจื™ืช - ื™ื“ืข ื‘ืฉื•ืจืช ื”ืคืงื•ื“ื” ืืคื™ืœื• ืœื ื ื“ืจืฉ. ืื™ื ื˜ื’ืจืฆื™ื” ืขื ืกืคืงื™ git ื—ื™ืฆื•ื ื™ื™ื - ื‘ื›ืžื” ืงืœื™ืงื™ื, ื™ื™ื‘ื•ื โ€‹โ€‹ืฉืœ ืžืคืชื—ื•ืช SSH ื›ื“ื™ ืœืฉืœื•ื— commits ืœืžืื’ืจ - ื’ื ื”-pipeline ืžื•ื’ื“ืจ ื‘ืงืœื•ืช ืืคื™ืœื• ืœื ืžืชื‘ื ื™ืช.

ืขืžื“ืช ืžื•ืฆื: ืžื” ื™ืฉ ืœืš ื•ืžื” ืืชื” ืจื•ืฆื”

ื™ืฉ ืœื ื•:

  • ืžืื’ืจ ื‘-GitLab.

ืื ื—ื ื• ืจื•ืฆื™ื:

  • ื”ืจื›ื‘ื” ื•ื‘ื“ื™ืงื” ืื•ื˜ื•ืžื˜ื™ืช ืขื‘ื•ืจ ื›ืœ ื‘ืงืฉืช ืžื™ื–ื•ื’,
  • ื‘ื ื™ื™ืช ื—ื‘ื™ืœื•ืช ืœื›ืœ ื‘ืงืฉืช ืžื™ื–ื•ื’ ื•ื“ื—ื™ืคื” ืœืžืืกื˜ืจ, ื‘ืชื ืื™ ืฉื™ืฉ ืฉื•ืจื” ืžืกื•ื™ืžืช ื‘ื”ื•ื“ืขืช ื”-commit,
  • ืฉืœื™ื—ืช ื—ื‘ื™ืœื•ืช ื‘ื ื•ื™ื•ืช ืœืคื™ื“ ืคืจื˜ื™ ื‘-Azure DevOps,
  • ื”ืจื›ื‘ื” ืฉืœ ืชื™ืขื•ื“ ื•ืคืจืกื•ื ื‘ื“ืคื™ GitLab,
  • ืชื’ื™ื!11

ื”ื“ืจื™ืฉื•ืช ื”ืžืชื•ืืจื•ืช ื ื•ืคืœื•ืช ื‘ืื•ืคืŸ ืื•ืจื’ื ื™ ืขืœ ืžื•ื“ืœ ื”ืฆื™ื ื•ืจ ื”ื‘ื:

  • ืฉืœื‘ 1 - ื”ืจื›ื‘ื”
    • ืื ื• ืื•ืกืคื™ื ืืช ื”ืงื•ื“, ืžืคืจืกืžื™ื ืืช ืงื‘ืฆื™ ื”ืคืœื˜ ื›ื—ืคืฆื™ื
  • ืฉืœื‘ 2 - ื‘ื“ื™ืงื”
    • ืื ื• ืžืงื‘ืœื™ื ื—ืคืฆื™ื ืžืฉืœื‘ ื”ื‘ื ื™ื™ื”, ืžืคืขื™ืœื™ื ื‘ื“ื™ืงื•ืช, ืื•ืกืคื™ื ื ืชื•ื ื™ ื›ื™ืกื•ื™ ืงื•ื“
  • ืฉืœื‘ 3 - ื”ื’ืฉื”
    • ืžืฉื™ืžื” 1 - ื‘ื ื” ืืช ื—ื‘ื™ืœืช ื”-nuget ื•ืฉืœื— ืื•ืชื” ืœ-Azure DevOps
    • ืžืฉื™ืžื” 2 - ืื ื• ืื•ืกืคื™ื ืืช ื”ืืชืจ ืž-xmldoc ื‘ืงื•ื“ ื”ืžืงื•ืจ ื•ืžืคืจืกืžื™ื ืื•ืชื• ื‘ื“ืคื™ GitLab

ื‘ื•ืื• ื ืชื—ื™ืœ!

ืื™ืกื•ืฃ ื”ืชืฆื•ืจื”

ื”ื›ื ืช ื—ืฉื‘ื•ื ื•ืช

  1. ืฆื•ืจ ื—ืฉื‘ื•ืŸ ื‘ Microsoft Azure

  2. ืœืš ืœ Devure ืฉืœ ืชื›ืœืช

  3. ืื ื—ื ื• ื™ื•ืฆืจื™ื ืคืจื•ื™ืงื˜ ื—ื“ืฉ

    1. ืฉื - ื›ืœ
    2. ื ืจืื•ืช - ื›ืœ
      ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

  4. ื›ืืฉืจ ืชืœื—ืฅ ืขืœ ื›ืคืชื•ืจ ืฆื•ืจ, ื”ืคืจื•ื™ื™ืงื˜ ื™ื•ื•ืฆืจ ื•ืชื•ืขื‘ืจ ืœื“ืฃ ืฉืœื•. ื‘ืขืžื•ื“ ื–ื”, ืชื•ื›ืœ ืœื”ืฉื‘ื™ืช ืชื›ื•ื ื•ืช ืžื™ื•ืชืจื•ืช ืขืœ ื™ื“ื™ ืžืขื‘ืจ ืœื”ื’ื“ืจื•ืช ื”ืคืจื•ื™ืงื˜ (ืงื™ืฉื•ืจ ืชื—ืชื•ืŸ ื‘ืจืฉื™ืžื” ืžืฉืžืืœ -> ืกืงื™ืจื” ื›ืœืœื™ืช -> ื‘ืœื•ืง ืฉื™ืจื•ืชื™ Azure DevOps)
    ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

  5. ืขื‘ื•ืจ ืืœ Atrifacts, ืœื—ืฅ ืขืœ ืฆื•ืจ ืขื“ื›ื•ืŸ

    1. ื”ื–ืŸ ืืช ืฉื ื”ืžืงื•ืจ
    2. ื‘ื—ืจ ื ืจืื•ืช
    3. ื‘ื˜ืœ ืืช ื”ืกื™ืžื•ืŸ ื›ืœื•ืœ ื—ื‘ื™ืœื•ืช ืžืžืงื•ืจื•ืช ืฆื™ื‘ื•ืจื™ื™ื ื ืคื•ืฆื™ื, ื›ื“ื™ ืฉื”ืžืงื•ืจ ืœื ื™ื”ืคื•ืš ืœืฉื‘ื•ื˜ ืฉืœ dump nuget
      ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

  6. ืœื—ืฅ ืขืœ ื”ืชื—ื‘ืจ ืœื”ื–ื ื”, ื‘ื—ืจ ื‘-Visual Studio, ื”ืขืชืง ืืช ื”ืžืงื•ืจ ืžื”ื’ื•ืฉ ื”ื’ื“ืจืช ืžื›ื•ื ื”
    ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

  7. ืขื‘ื•ืจ ืœื”ื’ื“ืจื•ืช ื”ื—ืฉื‘ื•ืŸ, ื‘ื—ืจ ืืกื™ืžื•ืŸ ื’ื™ืฉื” ืื™ืฉื™
    ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

  8. ืฆื•ืจ ืืกื™ืžื•ืŸ ื’ื™ืฉื” ื—ื“ืฉ

    1. ืฉื - ืฉืจื™ืจื•ืชื™
    2. ืืจื’ื•ืŸ - ืขื“ื›ื ื™
    3. ืชืงืฃ ืœืฉื ื” ืœื›ืœ ื”ื™ื•ืชืจ
    4. ื”ื™ืงืฃ - ืืจื™ื–ื”/ืงืจื™ืื” ื•ื›ืชื™ื‘ื”
      ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

  9. ื”ืขืชืง ืืช ื”ืืกื™ืžื•ืŸ ืฉื ื•ืฆืจ - ืœืื—ืจ ืกื’ื™ืจืช ื”ื—ืœื•ืŸ ื”ืžื•ื“ืืœื™, ื”ืขืจืš ืœื ื™ื”ื™ื” ื–ืžื™ืŸ

  10. ืขื‘ื•ืจ ืœื”ื’ื“ืจื•ืช ื”ืžืื’ืจ ื‘-GitLab, ื‘ื—ืจ ืืช ื”ื’ื“ืจื•ืช ื”-CI / CD
    ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

  11. ื”ืจื—ื‘ ืืช ื’ื•ืฉ ื”ืžืฉืชื ื™ื, ื”ื•ืกืฃ ืื—ื“ ื—ื“ืฉ

    1. ืฉื - ื›ืœ ืื—ื“ ืœืœื ืจื•ื•ื—ื™ื (ื™ื”ื™ื” ื–ืžื™ืŸ ื‘ืžืขื˜ืคืช ื”ืคืงื•ื“ื”)
    2. ืขืจืš - ืืกื™ืžื•ืŸ ื’ื™ืฉื” ืžืกืขื™ืฃ 9
    3. ื‘ื—ืจ ืžืฉืชื ื” ืžืกื›ื”
      ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

ื–ื” ืžืฉืœื™ื ืืช ื”ืชืฆื•ืจื” ื”ืžื•ืงื“ืžืช.

ื”ื›ื ืช ืžืกื’ืจืช ื”ืชืฆื•ืจื”

ื›ื‘ืจื™ืจืช ืžื—ื“ืœ, ืชืฆื•ืจืช CI/CD ื‘-GitLab ืžืฉืชืžืฉืช ื‘ืงื•ื‘ืฅ .gitlab-ci.yml ืžื”ืฉื•ืจืฉ ืฉืœ ื”ืžืื’ืจ. ืืชื” ื™ื›ื•ืœ ืœื”ื’ื“ื™ืจ ื ืชื™ื‘ ืฉืจื™ืจื•ืชื™ ืœืงื•ื‘ืฅ ื–ื” ื‘ื”ื’ื“ืจื•ืช ื”ืžืื’ืจ, ืืš ื‘ืžืงืจื” ื–ื” ืื™ืŸ ืฆื•ืจืš ื‘ื›ืš.

ื›ืคื™ ืฉื ื™ืชืŸ ืœืจืื•ืช ืžื”ืกื™ื•ืžืช, ื”ืงื•ื‘ืฅ ืžื›ื™ืœ ืชืฆื•ืจื” ื‘ืคื•ืจืžื˜ YAML. ื”ืชื™ืขื•ื“ ืžืคืจื˜ ืื™ืœื• ืžืคืชื—ื•ืช ื ื™ืชืŸ ืœื”ื›ื™ืœ ื‘ืจืžื” ื”ืขืœื™ื•ื ื” ืฉืœ ื”ืชืฆื•ืจื”, ื•ื‘ื›ืœ ืื—ืช ืžื”ืจืžื•ืช ื”ืžืงื•ื ื ื•ืช.

ืจืืฉื™ืช, ื ื•ืกื™ืฃ ืงื™ืฉื•ืจ ืœืชืžื•ื ืช ื”-docker ื‘ืงื•ื‘ืฅ ื”ืชืฆื•ืจื”, ื‘ื” ื™ื‘ื•ืฆืขื• ื”ืžืฉื™ืžื•ืช. ื‘ืฉื‘ื™ืœ ื–ื” ืื ื—ื ื• ืžื•ืฆืื™ื ื“ืฃ ืชืžื•ื ื•ืช .Net Core ื‘- Docker Hub. ื‘ืชื•ืš GitHub ื™ืฉ ืžื“ืจื™ืš ืžืคื•ืจื˜ ื‘ืื™ื–ื• ืชืžื•ื ื” ืœื‘ื—ื•ืจ ืœืžืฉื™ืžื•ืช ืฉื•ื ื•ืช. ืชืžื•ื ื” ืขื .Net Core 3.1 ืžืชืื™ืžื” ืœื ื• ืœื‘ื ื•ืช, ืื– ืืชื ืžื•ื–ืžื ื™ื ืœื”ื•ืกื™ืฃ ืืช ื”ืฉื•ืจื” ื”ืจืืฉื•ื ื” ืœืชืฆื•ืจื”

image: mcr.microsoft.com/dotnet/core/sdk:3.1

ื›ืขืช, ื›ืืฉืจ ื”ืฆื™ื ื•ืจ ื™ื•ืฉืง ืžืžืื’ืจ ื”ืชืžื•ื ื•ืช ืฉืœ ืžื™ืงืจื•ืกื•ืคื˜, ืชื•ืจื™ื“ ื”ืชืžื•ื ื” ืฉืฆื•ื™ื ื”, ื‘ื” ื™ื‘ื•ืฆืขื• ื›ืœ ื”ืžืฉื™ืžื•ืช ืžื”ืชืฆื•ืจื”.

ื”ืฉืœื‘ ื”ื‘ื ื”ื•ื ืœื”ื•ืกื™ืฃ ืฉืœื‘ืฉืœ. ื›ื‘ืจื™ืจืช ืžื—ื“ืœ, GitLab ืžื’ื“ื™ืจ 5 ืฉืœื‘ื™ื:

  • .pre - ืžื‘ื•ืฆืข ืขื“ ื›ืœ ื”ืฉืœื‘ื™ื,
  • .post - ืžื‘ื•ืฆืข ืœืื—ืจ ื›ืœ ื”ืฉืœื‘ื™ื,
  • build - ืจืืฉื•ืŸ ืื—ืจื™ .pre ืฉืœื‘,
  • test - ืฉืœื‘ ืฉื ื™,
  • deploy - ื”ืฉืœื‘ ื”ืฉืœื™ืฉื™.

ืขื ื–ืืช, ืฉื•ื ื“ื‘ืจ ืœื ืžื•ื ืข ืžืžืš ืœื”ื›ืจื™ื– ืขืœื™ื”ื ื‘ืžืคื•ืจืฉ. ื”ืกื“ืจ ืฉื‘ื• ืžื•ืคื™ืขื™ื ื”ืฉืœื‘ื™ื ืžืฉืคื™ืข ืขืœ ืกื“ืจ ื‘ื™ืฆื•ืขื. ืœืžืขืŸ ื”ืฉืœืžื•ืช, ื‘ื•ืื• ื ื•ืกื™ืฃ ืœืชืฆื•ืจื”:

stages:
  - build
  - test
  - deploy

ืœืฆื•ืจืš ืื™ืชื•ืจ ื‘ืื’ื™ื, ื”ื’ื™ื•ื ื™ ืœืงื‘ืœ ืžื™ื“ืข ืขืœ ื”ืกื‘ื™ื‘ื” ืฉื‘ื” ื”ืžืฉื™ืžื•ืช ืžื‘ื•ืฆืขื•ืช. ื‘ื•ืื• ื ื•ืกื™ืฃ ืกื˜ ื’ืœื•ื‘ืœื™ ืฉืœ ืคืงื•ื“ื•ืช ืฉื™ื‘ื•ืฆืขื• ืœืคื ื™ ื›ืœ ืžืฉื™ืžื” ืขื before_script:

before_script:
  - $PSVersionTable.PSVersion
  - dotnet --version
  - nuget help | select-string Version

ื ื•ืชืจ ืœื”ื•ืกื™ืฃ ืœืคื—ื•ืช ืžืฉื™ืžื” ืื—ืช ื›ื“ื™ ืฉื›ืืฉืจ ื”-commits ื™ื™ืฉืœื—ื•, ื”-pipeline ื™ืชื—ื™ืœ. ืœืขืช ืขืชื”, ื‘ื•ืื• ื ื•ืกื™ืฃ ืžืฉื™ืžื” ืจื™ืงื” ืœื”ื“ื’ืžื”:

dummy job:
  script:
    - echo ok

ืื ื—ื ื• ืžืชื—ื™ืœื™ื ืื™ืžื•ืช, ืžืงื‘ืœื™ื ื”ื•ื“ืขื” ืฉื”ื›ืœ ื‘ืกื“ืจ, ืื ื—ื ื• ืžืชื—ื™ื™ื‘ื™ื, ืื ื—ื ื• ื“ื•ื—ืคื™ื, ืื ื—ื ื• ืžืกืชื›ืœื™ื ืขืœ ื”ืชื•ืฆืื•ืช ื‘ืืชืจ... ื•ืžืงื‘ืœื™ื ืฉื’ื™ืืช ืกืงืจื™ืคื˜ - bash: .PSVersion: command not found. wtf?

ื”ื›ืœ ื”ื’ื™ื•ื ื™ - ื›ื‘ืจื™ืจืช ืžื—ื“ืœ, ืจืฆื™ื (ื”ืื—ืจืื™ื ืขืœ ื‘ื™ืฆื•ืข ืกืงืจื™ืคื˜ื™ื ืฉืœ ืžืฉื™ืžื•ืช ื•ืžืกื•ืคืงื™ื ืขืœ ื™ื“ื™ GitLab) ืžืฉืชืžืฉื™ื bash ื›ื“ื™ ืœื‘ืฆืข ืคืงื•ื“ื•ืช. ืืชื” ื™ื›ื•ืœ ืœืชืงืŸ ื–ืืช ืขืœ ื™ื“ื™ ืฆื™ื•ืŸ ืžืคื•ืจืฉ ื‘ืชื™ืื•ืจ ื”ืžืฉื™ืžื” ืื™ืœื• ืชื’ื™ื ืฆืจื™ื›ื™ื ืœื”ื™ื•ืช ืœืจืฅ ื”ืฆื™ื ื•ืจ ื”ืžื‘ืฆืข:

dummy job on windows:
  script:
    - echo ok
  tags:
    - windows

ื’ื“ื•ืœ! ื”ืฆื™ื ื•ืจ ืคื•ืขืœ ื›ืขืช.

ืงื•ืจื ืงืฉื•ื‘, ืœืื—ืจ ืฉื—ื–ืจ ืขืœ ื”ืฉืœื‘ื™ื ื”ืžืฆื•ื™ื ื™ื, ื™ื‘ื—ื™ืŸ ื›ื™ ื”ืžืฉื™ืžื” ื”ื•ืฉืœืžื” ื‘ืฉืœื‘ test, ืœืžืจื•ืช ืฉืœื ืฆื™ื™ื ื• ืืช ื”ืฉืœื‘. ื›ืคื™ ืฉืืชื” ื™ื›ื•ืœ ืœื ื—ืฉ test ื”ื•ื ืฉืœื‘ ื‘ืจื™ืจืช ื”ืžื—ื“ืœ.

ื‘ื•ืื• ื ืžืฉื™ืš ืœื™ืฆื•ืจ ืืช ืฉืœื“ ื”ืชืฆื•ืจื” ืขืœ ื™ื“ื™ ื”ื•ืกืคืช ื›ืœ ื”ืžืฉื™ืžื•ืช ืฉืชื•ืืจื• ืœืขื™ืœ:

build job:
  script:
    - echo "building..."
  tags:
    - windows
  stage: build

test and cover job:
  script:
    - echo "running tests and coverage analysis..."
  tags:
    - windows
  stage: test

pack and deploy job:
  script:
    - echo "packing and pushing to nuget..."
  tags:
    - windows
  stage: deploy

pages:
  script:
    - echo "creating docs..."
  tags:
    - windows
  stage: deploy

ืงื™ื‘ืœื ื• ืฆื™ื ื•ืจ ืœื ืคื•ื ืงืฆื™ื•ื ืœื™ ื‘ืžื™ื•ื—ื“, ืื‘ืœ ื‘ื›ืœ ื–ืืช ื ื›ื•ืŸ.

ื”ื’ื“ืจืช ื˜ืจื™ื’ืจื™ื

ื‘ืฉืœ ื”ืขื•ื‘ื“ื” ืฉืœื ืฆื•ื™ื ื• ืžืกื ื ื™ ื˜ืจื™ื’ืจ ืขื‘ื•ืจ ืืฃ ืื—ืช ืžื”ืžืฉื™ืžื•ืช, ื”ืฆื™ื ื•ืจ ื™ืขืฉื” ื–ืืช ื‘ืื•ืคืŸ ืžืœื ืœื”ืชื‘ืฆืข ื‘ื›ืœ ืคืขื ืฉ-commit ื ื“ื—ืฃ ืœืžืื’ืจ. ืžื›ื™ื•ื•ืŸ ืฉื–ื• ืœื ื”ื”ืชื ื”ื’ื•ืช ื”ืจืฆื•ื™ื” ื‘ืื•ืคืŸ ื›ืœืœื™, ื ื’ื“ื™ืจ ืžืกื ื ื™ ื˜ืจื™ื’ืจ ืœืžืฉื™ืžื•ืช.

ื ื™ืชืŸ ืœื”ื’ื“ื™ืจ ืžืกื ื ื™ื ื‘ืฉื ื™ ืคื•ืจืžื˜ื™ื: ืจืง/ืœืžืขื˜ ะธ ื›ืœืœื™. ื‘ืงืฆืจื”, only/except ืžืืคืฉืจ ืœืš ืœื”ื’ื“ื™ืจ ืžืกื ื ื™ื ืœืคื™ ื˜ืจื™ื’ืจื™ื (merge_request, ืœืžืฉืœ - ืžื’ื“ื™ืจ ืืช ื”ืžืฉื™ืžื” ืœื‘ื™ืฆื•ืข ื‘ื›ืœ ืคืขื ืฉื ื•ืฆืจืช ื‘ืงืฉืช pull ื•ื‘ื›ืœ ืคืขื ืฉื ืฉืœื—ื•ืช commits ืœืกื ื™ืฃ ืฉื”ื•ื ื”ืžืงื•ืจ ื‘ื‘ืงืฉืช ื”ืžื™ื–ื•ื’) ื•ืฉืžื•ืช ืกื ื™ืคื™ื (ื›ื•ืœืœ ืฉื™ืžื•ืฉ ื‘ื‘ื™ื˜ื•ื™ื™ื ืจื’ื•ืœืจื™ื™ื); rules ืžืืคืฉืจ ืœืš ืœื”ืชืื™ื ืื™ืฉื™ืช ืงื‘ื•ืฆื” ืฉืœ ืชื ืื™ื ื•ื‘ืื•ืคืŸ ืื•ืคืฆื™ื•ื ืœื™ ืœืฉื ื•ืช ืืช ืชื ืื™ ื‘ื™ืฆื•ืข ื”ืžืฉื™ืžื” ื‘ื”ืชืื ืœื”ืฆืœื—ืช ื”ืžืฉื™ืžื•ืช ื”ืงื•ื“ืžื•ืช (when ื‘- GitLab CI/CD).

ื ื–ื›ื™ืจ ืกื˜ ื“ืจื™ืฉื•ืช - ื”ืจื›ื‘ื” ื•ื‘ื“ื™ืงื” ืจืง ืœื‘ืงืฉืช ืžื™ื–ื•ื’, ืืจื™ื–ื” ื•ืฉืœื™ื—ื” ืœ-Azure DevOps - ืœื‘ืงืฉืช ืžื™ื–ื•ื’ ื•ื“ื—ื™ืคื•ืช ืœืžืืกื˜ืจ, ื”ืคืงืช ืชื™ืขื•ื“ - ืœื“ื—ื™ืคื•ืช ืœืžืืกื˜ืจ.

ืจืืฉื™ืช, ื”ื‘ื” ื ื’ื“ื™ืจ ืืช ืžืฉื™ืžืช ื‘ื ื™ื™ืช ื”ืงื•ื“ ืขืœ ื™ื“ื™ ื”ื•ืกืคืช ื›ืœืœ ืฉืคื•ืขืœ ืจืง ื‘ื‘ืงืฉืช ืžื™ื–ื•ื’:

build job:
  # snip
  only:
    - merge_request

ื›ืขืช ื”ื‘ื” ื ื’ื“ื™ืจ ืืช ืžืฉื™ืžืช ื”ืืจื™ื–ื” ืœื”ืคืขืœืช ื‘ืงืฉืช ื”ืžื™ื–ื•ื’ ื•ื ื•ืกื™ืฃ ื”ืชื—ื™ื™ื‘ื•ื™ื•ืช ืœืžืืกื˜ืจ:

pack and deploy job:
  # snip
  only:
    - merge_request
    - master

ื›ืคื™ ืฉืืชื” ื™ื›ื•ืœ ืœืจืื•ืช, ื”ื›ืœ ืคืฉื•ื˜ ื•ืคืฉื•ื˜.

ืืชื” ื™ื›ื•ืœ ื’ื ืœื”ื’ื“ื™ืจ ืืช ื”ืžืฉื™ืžื” ืœื”ืคืขืœื” ืจืง ืื ื ื•ืฆืจืช ื‘ืงืฉืช ืžื™ื–ื•ื’ ืขื ื™ืขื“ ืกืคืฆื™ืคื™ ืื• ืขื ืฃ ืžืงื•ืจ ืกืคืฆื™ืคื™:

  rules:
    - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"

ื‘ืชื ืื™ื, ืืชื” ื™ื›ื•ืœ ืœื”ืฉืชืžืฉ ืžืฉืชื ื™ื ื”ืžื•ืคื™ืขื™ื ื›ืืŸ; ื›ืœืœื™ื rules ืœื ืชื•ืื ืืช ื”ื›ืœืœื™ื only/except.

ื”ื’ื“ืจืช ืฉืžื™ืจืช ื—ืคืฆื™ื

ื‘ืžื”ืœืš ืžืฉื™ืžื” build job ื ื™ืฆื•ืจ ื—ืคืฆื™ื ืฉื ื™ืชืŸ ืœืขืฉื•ืช ื‘ื”ื ืฉื™ืžื•ืฉ ื—ื•ื–ืจ ื‘ืžืฉื™ืžื•ืช ื”ื‘ืื•ืช. ืœืฉื ื›ืš, ืขืœื™ืš ืœื”ื•ืกื™ืฃ ืืช ื”ื ืชื™ื‘ื™ื ืœืชืฆื•ืจืช ื”ืžืฉื™ืžื”, ืืช ื”ืงื‘ืฆื™ื ืฉืœืื•ืจื›ื ืชืฆื˜ืจืš ืœืฉืžื•ืจ ื•ืœืขืฉื•ืช ืฉื™ืžื•ืฉ ื—ื•ื–ืจ ื‘ืžืฉื™ืžื•ืช ื”ื‘ืื•ืช, ืœืžืคืชื— artifacts:

build job:
  # snip
  artifacts:
    paths:
      - path/to/build/artifacts
      - another/path
      - MyCoolLib.*/bin/Release/*

ื ืชื™ื‘ื™ื ืชื•ืžื›ื™ื ื‘ืชื•ื•ื™ื ื›ืœืœื™ื™ื, ืžื” ืฉื‘ื”ื—ืœื˜ ืžืงืœ ืขืœ ื”ื’ื“ืจืชื.

ืื ืžืฉื™ืžื” ื™ื•ืฆืจืช ื—ืคืฆื™ื, ืื– ื›ืœ ืžืฉื™ืžื” ืฉืœืื—ืจ ืžื›ืŸ ืชื•ื›ืœ ืœื’ืฉืช ืืœื™ื”ื - ื”ื ื™ืžื•ืงืžื• ื‘ืื•ืชื ื ืชื™ื‘ื™ื ื‘ื™ื—ืก ืœืฉื•ืจืฉ ื”ืžืื’ืจ ืฉื ืืกืคื• ืžื”ืžืฉื™ืžื” ื”ืžืงื•ืจื™ืช. ื—ืคืฆื™ื ื–ืžื™ื ื™ื ื’ื ืœื”ื•ืจื“ื” ื‘ืืชืจ.

ื›ืขืช, ื›ืืฉืจ ื™ืฉ ืœื ื• ืืช ืžืกื’ืจืช ื”ืชืฆื•ืจื” ืžื•ื›ื ื” (ื•ื ื‘ื“ืงื”), ืื ื• ื™ื›ื•ืœื™ื ืœื”ืžืฉื™ืš ืœื›ืชื™ื‘ืช ืกืงืจื™ืคื˜ื™ื ืขื‘ื•ืจ ืžืฉื™ืžื•ืช ื‘ืคื•ืขืœ.

ืื ื—ื ื• ื›ื•ืชื‘ื™ื ืชืกืจื™ื˜ื™ื

ืื•ืœื™, ืคืขื, ื‘ื’ืœืงืกื™ื” ืจื—ื•ืงื”, ืจื—ื•ืงื”, ื‘ื ื™ื™ืช ืคืจื•ื™ืงื˜ื™ื (ื›ื•ืœืœ ืืœื” ื‘-.net) ืžืฉื•ืจืช ื”ืคืงื•ื“ื” ื”ื™ื™ืชื” ื›ืื‘. ืขื›ืฉื™ื• ืืชื” ื™ื›ื•ืœ ืœื‘ื ื•ืช, ืœื‘ื“ื•ืง ื•ืœืคืจืกื ืืช ื”ืคืจื•ื™ืงื˜ ื‘-3 ืฆื•ื•ืชื™ื:

dotnet build
dotnet test
dotnet pack

ื‘ืื•ืคืŸ ื˜ื‘ืขื™, ื™ืฉื ื ื›ืžื” ื ื™ื•ืื ืกื™ื ืฉื‘ื’ืœืœื ื ืกื‘ืš ืžืขื˜ ืืช ื”ืคืงื•ื“ื•ืช.

  1. ืื ื—ื ื• ืจื•ืฆื™ื ื‘ื ื™ื™ืช ืฉื—ืจื•ืจ, ืœื ื‘ื ื™ื™ืช ื‘ืื’ื™ื, ืื– ืื ื—ื ื• ืžื•ืกื™ืคื™ื ืœื›ืœ ืคืงื•ื“ื” -c Release
  2. ื‘ืขืช ื”ื‘ื“ื™ืงื”, ืื ื• ืจื•ืฆื™ื ืœืืกื•ืฃ ื ืชื•ื ื™ ื›ื™ืกื•ื™ ืงื•ื“, ื•ืœื›ืŸ ืขืœื™ื ื• ืœื›ืœื•ืœ ืžื ืชื— ื›ื™ืกื•ื™ ื‘ืกืคืจื™ื•ืช ื”ื‘ื“ื™ืงื”:
    1. ื”ื•ืกืฃ ืืช ื”ื—ื‘ื™ืœื” ืœื›ืœ ืกืคืจื™ื•ืช ื”ื‘ื“ื™ืงื” coverlet.msbuild: dotnet add package coverlet.msbuild ืžืชื™ืงื™ื™ืช ื”ืคืจื•ื™ืงื˜
    2. ื”ื•ืกืฃ ืœืคืงื•ื“ืช ื”ืคืขืœืช ื”ืžื‘ื—ืŸ /p:CollectCoverage=true
    3. ื”ื•ืกืฃ ืžืคืชื— ืœืชืฆื•ืจืช ืžืฉื™ืžืช ื”ื‘ื“ื™ืงื” ื›ื“ื™ ืœืงื‘ืœ ืชื•ืฆืื•ืช ื›ื™ืกื•ื™ (ืจืื” ืœื”ืœืŸ)
  3. ื‘ืขืช ืืจื™ื–ื” ืฉืœ ื”ืงื•ื“ ื‘ื—ื‘ื™ืœื•ืช nuget, ื”ื’ื“ืจ ืืช ืกืคืจื™ื™ืช ื”ืคืœื˜ ืขื‘ื•ืจ ื”ื—ื‘ื™ืœื•ืช: -o .

ืื™ืกื•ืฃ ื ืชื•ื ื™ ื›ื™ืกื•ื™ ืงื•ื“

ืœืื—ืจ ื”ืคืขืœืช ื”ื‘ื“ื™ืงื•ืช, Coverlet ืžื“ืคื™ืก ืกื˜ื˜ื™ืกื˜ื™ืงื•ืช ื”ืคืขืœื” ืœืงื•ื ืกื•ืœื”:

Calculating coverage result...
  Generating report 'C:Usersxxxsourcereposmy-projectmyProject.testscoverage.json'

+-------------+--------+--------+--------+
| Module      | Line   | Branch | Method |
+-------------+--------+--------+--------+
| project 1   | 83,24% | 66,66% | 92,1%  |
+-------------+--------+--------+--------+
| project 2   | 87,5%  | 50%    | 100%   |
+-------------+--------+--------+--------+
| project 3   | 100%   | 83,33% | 100%   |
+-------------+--------+--------+--------+

+---------+--------+--------+--------+
|         | Line   | Branch | Method |
+---------+--------+--------+--------+
| Total   | 84,27% | 65,76% | 92,94% |
+---------+--------+--------+--------+
| Average | 90,24% | 66,66% | 97,36% |
+---------+--------+--------+--------+

GitLab ืžืืคืฉืจืช ืœืฆื™ื™ืŸ ื‘ื™ื˜ื•ื™ ืจื’ื•ืœืจื™ ื›ื“ื™ ืœืงื‘ืœ ื ืชื•ื ื™ื ืกื˜ื˜ื™ืกื˜ื™ื™ื, ืฉืื•ืชื ื ื™ืชืŸ ืœืงื‘ืœ ื‘ืฆื•ืจื” ืฉืœ ืชื’. ื”ื‘ื™ื˜ื•ื™ ื”ืจื’ื•ืœืจื™ ืžืฆื•ื™ืŸ ื‘ื”ื’ื“ืจื•ืช ื”ืžืฉื™ืžื” ืขื ื”ืžืคืชื— coverage; ื”ื‘ื™ื˜ื•ื™ ื—ื™ื™ื‘ ืœื”ื›ื™ืœ ืงื‘ื•ืฆืช ืœื›ื™ื“ื”, ืฉืขืจื›ื” ื™ื•ืขื‘ืจ ืœืชื’:

test and cover job:
  # snip
  coverage: /|s*Totals*|s*(d+[,.]d+%)/

ื›ืืŸ ืื ื• ืžืงื‘ืœื™ื ื ืชื•ื ื™ื ืกื˜ื˜ื™ืกื˜ื™ื™ื ืžืงื• ืขื ื›ื™ืกื•ื™ ืงื• ื›ื•ืœืœ.

ืคืจืกื ื—ื‘ื™ืœื•ืช ื•ืชื™ืขื•ื“

ืฉืชื™ ื”ืคืขื•ืœื•ืช ืžืชื•ื›ื ื ื•ืช ืœืฉืœื‘ ื”ืื—ืจื•ืŸ ืฉืœ ื”ืฆื™ื ื•ืจ - ืžืื—ืจ ืฉื”ื”ืจื›ื‘ื” ื•ื”ื‘ื“ื™ืงื•ืช ืขื‘ืจื•, ื ื•ื›ืœ ืœืฉืชืฃ ืืช ื”ืขื•ืœื ื‘ื”ืชืคืชื—ื•ื™ื•ืช ืฉืœื ื•.

ืจืืฉื™ืช, ืฉืงื•ืœ ืœืคืจืกื ื‘ืžืงื•ืจ ื”ื—ื‘ื™ืœื”:

  1. ืื ืœืคืจื•ื™ืงื˜ ืื™ืŸ ืงื•ื‘ืฅ ืชืฆื•ืจื” ืฉืœ nuget (nuget.config), ืฆื•ืจ ืื—ื“ ื—ื“ืฉ: dotnet new nugetconfig

    ื‘ืฉื‘ื™ืœ ืžื”: ื™ื™ืชื›ืŸ ืฉืœืชืžื•ื ื” ืื™ืŸ ื’ื™ืฉืช ื›ืชื™ื‘ื” ืœืชืฆื•ืจื•ืช ื’ืœื•ื‘ืœื™ื•ืช (ืžืฉืชืžืฉ ื•ืžื›ื•ื ื”). ื›ื“ื™ ืœื ืœืชืคื•ืก ืฉื’ื™ืื•ืช, ืื ื—ื ื• ืคืฉื•ื˜ ื™ื•ืฆืจื™ื ืชืฆื•ืจื” ืžืงื•ืžื™ืช ื—ื“ืฉื” ื•ืขื•ื‘ื“ื™ื ืื™ืชื”.

  2. ื‘ื•ืื• ื ื•ืกื™ืฃ ืžืงื•ืจ ื—ื‘ื™ืœื” ื—ื“ืฉ ืœืชืฆื•ืจื” ื”ืžืงื•ืžื™ืช: nuget sources add -name <name> -source <url> -username <organization> -password <gitlab variable> -configfile nuget.config -StorePasswordInClearText
    1. name - ืฉื ืžืงื•ืจ ืžืงื•ืžื™, ืœื ืงืจื™ื˜ื™
    2. url - URL ืฉืœ ื”ืžืงื•ืจ ืžืฉืœื‘ "ื”ื›ื ืช ื—ืฉื‘ื•ื ื•ืช", ืขืž' 6
    3. organization - ืฉื ื”ืืจื’ื•ืŸ ื‘-Azure DevOps
    4. gitlab variable - ืฉื ื”ืžืฉืชื ื” ืขื ืืกื™ืžื•ืŸ ื”ื’ื™ืฉื” ืฉื ื•ืกืฃ ืœ-GitLab ("ื”ื›ื ืช ื—ืฉื‘ื•ื ื•ืช", ืขืž' 11). ื‘ืื•ืคืŸ ื˜ื‘ืขื™, ื‘ืคื•ืจืžื˜ $variableName
    5. -StorePasswordInClearText - ืคืจื™ืฆื” ื›ื“ื™ ืœืขืงื•ืฃ ืืช ืฉื’ื™ืืช ื”ื’ื™ืฉื” ื ื“ื—ืชื” (ืื ื™ ืœื ื”ืจืืฉื•ืŸ ืฉื“ืจืš ืขืœ ื”ืžื’ืจืคื” ื”ื–ื•)
    6. ื‘ืžืงืจื” ืฉืœ ืฉื’ื™ืื•ืช, ื™ื™ืชื›ืŸ ืฉื™ื”ื™ื” ืฉื™ืžื•ืฉื™ ืœื”ื•ืกื™ืฃ -verbosity detailed
  3. ืฉืœื™ื—ืช ื”ื—ื‘ื™ืœื” ืœืžืงื•ืจ: nuget push -source <name> -skipduplicate -apikey <key> *.nupkg
    1. ืื ื—ื ื• ืฉื•ืœื—ื™ื ืืช ื›ืœ ื”ื—ื‘ื™ืœื•ืช ืžื”ืกืคืจื™ื™ื” ื”ื ื•ื›ื—ื™ืช, ืื– *.nupkg.
    2. name - ืžื”ืฉืœื‘ ืฉืœืžืขืœื”.
    3. key - ื›ืœ ืฉื•ืจื”. ื‘-Azure DevOps, ื‘ื—ืœื•ืŸ Connect to feed, ื”ื“ื•ื’ืžื” ื”ื™ื ืชืžื™ื“ ื”ืงื• az.
    4. -skipduplicate - ื›ืืฉืจ ืžื ืกื™ื ืœืฉืœื•ื— ื—ื‘ื™ืœื” ืฉื›ื‘ืจ ืงื™ื™ืžืช ืœืœื ืžืคืชื— ื–ื”, ื”ืžืงื•ืจ ื™ื—ื–ื™ืจ ืฉื’ื™ืื” 409 Conflict; ืขื ื”ืžืคืชื—, ื”ืฉืœื™ื—ื” ืชื™ื“ืœื’.

ืขื›ืฉื™ื• ื‘ื•ืื• ื ื’ื“ื™ืจ ืืช ื™ืฆื™ืจืช ื”ืชื™ืขื•ื“:

  1. ืจืืฉื™ืช, ื‘ืžืื’ืจ, ื‘ืขื ืฃ ื”ืžืืกื˜ืจ, ืื ื• ืžืืชื—ืœื™ื ืืช ืคืจื•ื™ืงื˜ docfx. ืœืฉื ื›ืš, ื”ืคืขืœ ืืช ื”ืคืงื•ื“ื” ืžื”ืฉื•ืจืฉ docfx init ื•ืœื”ื’ื“ื™ืจ ื‘ืื•ืคืŸ ืื™ื ื˜ืจืืงื˜ื™ื‘ื™ ืืช ื”ืคืจืžื˜ืจื™ื ื”ืžืจื›ื–ื™ื™ื ืœืชื™ืขื•ื“ ื”ื‘ื ื™ื™ืŸ. ืชื™ืื•ืจ ืžืคื•ืจื˜ ืฉืœ ื”ื’ื“ืจืช ื”ืคืจื•ื™ืงื˜ ื”ืžื™ื ื™ืžืœื™ืช ื›ืืŸ.
    1. ื‘ืขืช ื”ื’ื“ืจืช ื”ืชืฆื•ืจื”, ื—ืฉื•ื‘ ืœืฆื™ื™ืŸ ืืช ืกืคืจื™ื™ืช ื”ืคืœื˜ ..public - GitLab ื›ื‘ืจื™ืจืช ืžื—ื“ืœ ืœื•ืงื— ืืช ืชื•ื›ืŸ ื”ืชื™ืงื™ื” ื”ืฆื™ื‘ื•ืจื™ืช ื‘ืฉื•ืจืฉ ื”ืžืื’ืจ ื›ืžืงื•ืจ ืขื‘ื•ืจ Pages. ื›ื™ ื”ืคืจื•ื™ืงื˜ ื™ืžื•ืงื ื‘ืชื™ืงื™ื™ื” ื”ืžืงื•ื ื ืช ื‘ืžืื’ืจ - ื”ื•ืกืฃ ืคืœื˜ ืœืจืžื” ืœืžืขืœื” ื‘ื ืชื™ื‘.
  2. ื‘ื•ืื• ื ื“ื—ื•ืฃ ืืช ื”ืฉื™ื ื•ื™ื™ื ืœ-GitLab.
  3. ื”ื•ืกืฃ ืžืฉื™ืžื” ืœืชืฆื•ืจืช ื”ืฆื™ื ื•ืจ pages (ืžื™ืœื” ืฉืžื•ืจื” ืœืžืฉื™ืžื•ืช ืคืจืกื•ื ืืชืจื™ื ื‘ื“ืคื™ GitLab):
    1. ืชึทืกืจึดื™ื˜:
      1. nuget install docfx.console -version 2.51.0 - ื”ืชืงืŸ docfx; ื”ื’ืจืกื” ืฆื•ื™ื ื” ื›ื“ื™ ืœื”ื‘ื˜ื™ื— ืฉื ืชื™ื‘ื™ ื”ืชืงื ืช ื”ื—ื‘ื™ืœื” ื ื›ื•ื ื™ื.
      2. .docfx.console.2.51.0toolsdocfx.exe .docfx_projectdocfx.json - ืื™ืกื•ืฃ ืชื™ืขื•ื“
    2. ื—ืคืฆื™ ืฆื•ืžืช:

pages:
  # snip
  artifacts:
    paths:
      - public

ืกื˜ื™ื™ื” ืœื™ืจื™ืช ืขืœ docfx

ื‘ืขื‘ืจ, ื‘ืขืช ื”ื’ื“ืจืช ืคืจื•ื™ื™ืงื˜, ืฆื™ื™ื ืชื™ ืืช ืžืงื•ืจ ื”ืงื•ื“ ืขื‘ื•ืจ ื”ืชื™ืขื•ื“ ื›ืงื•ื‘ืฅ ืคืชืจื•ืŸ. ื”ื—ื™ืกืจื•ืŸ ื”ืขื™ืงืจื™ ื”ื•ื ืฉื ื•ืฆืจ ืชื™ืขื•ื“ ื’ื ืขื‘ื•ืจ ืคืจื•ื™ืงื˜ื™ ื‘ื“ื™ืงื”. ื‘ืžืงืจื” ืฉื–ื” ืœื ื”ื›ืจื—ื™, ืืชื” ื™ื›ื•ืœ ืœื”ื’ื“ื™ืจ ืขืจืš ื–ื” ืœืฆื•ืžืช metadata.src:

{
  "metadata": [
    {
      "src": [
        {
          "src": "../",
          "files": [
            "**/*.csproj"
          ],
          "exclude":[
            "*.tests*/**"
          ]
        }
      ],
      // --- snip ---
    },
    // --- snip ---
  ],
  // --- snip ---
}

  1. metadata.src.src: "../" - ืื ื—ื ื• ืขื•ืœื™ื ืจืžื” ืื—ืช ืœืžืขืœื” ื‘ื™ื—ืก ืœืžื™ืงื•ื docfx.json, ื›ื™ ื‘ืชื‘ื ื™ื•ืช, ื—ื™ืคื•ืฉ ื‘ืขืฅ ื”ืกืคืจื™ื•ืช ืœื ืขื•ื‘ื“.
  2. metadata.src.files: ["**/*.csproj"] - ื“ืคื•ืก ื’ืœื•ื‘ืœื™, ืื ื• ืื•ืกืคื™ื ืืช ื›ืœ ื”ืคืจื•ื™ืงื˜ื™ื ืฉืœ C # ืžื›ืœ ื”ืกืคืจื™ื•ืช.
  3. metadata.src.exclude: ["*.tests*/**"] - ื“ืคื•ืก ื’ืœื•ื‘ืœื™, ืืœ ืชื›ืœื•ืœ ื”ื›ืœ ืžืชื™ืงื™ื•ืช ืขื .tests ื‘ื›ื•ืชืจืช

ืจืžื” ื—ืœืงื™ืช

ืชืฆื•ืจื” ืคืฉื•ื˜ื” ื›ื–ื• ื™ื›ื•ืœื” ืœื”ื™ื•ื•ืฆืจ ืชื•ืš ื—ืฆื™ ืฉืขื” ื•ื›ืžื” ื›ื•ืกื•ืช ืงืคื” ื‘ืœื‘ื“, ืฉืชืืคืฉืจ ืœื›ื ืœื‘ื“ื•ืง ืฉื”ืงื•ื“ ื‘ื ื•ื™ ื•ื”ื‘ื“ื™ืงื•ืช ืขื•ื‘ืจื•ืช, ืœื‘ื ื•ืช ื—ื‘ื™ืœื” ื—ื“ืฉื”, ืœืขื“ื›ืŸ ืืช ื”ืชื™ืขื•ื“ ื•ืœืฉืžื— ืืช ื”ืขื™ืŸ ื‘ื™ื•ืคื™ ืชื’ื™ื ื‘-README ืฉืœ ื”ืคืจื•ื™ืงื˜ ืขื ื›ืœ ื‘ืงืฉืช ืžื™ื–ื•ื’ ื•ืฉืœื™ื—ื” ืœืžืืกื˜ืจ.

Final .gitlab-ci.yml

image: mcr.microsoft.com/dotnet/core/sdk:3.1

before_script:
  - $PSVersionTable.PSVersion
  - dotnet --version
  - nuget help | select-string Version

stages:
  - build
  - test
  - deploy

build job:
  stage: build
  script:
    - dotnet build -c Release
  tags:
    - windows
  only:
    - merge_requests
    - master
  artifacts:
    paths:
      - your/path/to/binaries

test and cover job:
  stage: test
  tags:
    - windows
  script:
    - dotnet test -c Release /p:CollectCoverage=true
  coverage: /|s*Totals*|s*(d+[,.]d+%)/
  only:
    - merge_requests
    - master

pack and deploy job:
  stage: deploy
  tags:
    - windows
  script:
    - dotnet pack -c Release -o .
    - dotnet new nugetconfig
    - nuget sources add -name feedName -source https://pkgs.dev.azure.com/your-organization/_packaging/your-feed/nuget/v3/index.json -username your-organization -password $nugetFeedToken -configfile nuget.config -StorePasswordInClearText
    - nuget push -source feedName -skipduplicate -apikey az *.nupkg
  only:
    - master

pages:
  tags:
    - windows
  stage: deploy
  script:
    - nuget install docfx.console -version 2.51.0
    - $env:path = "$env:path;$($(get-location).Path)"
    - .docfx.console.2.51.0toolsdocfx.exe .docfxdocfx.json
  artifacts:
    paths:
      - public
  only:
    - master

ืื ื›ื‘ืจ ืžื“ื‘ืจื™ื ืขืœ ืชื’ื™ื

ื‘ื’ืœืœื, ืื—ืจื™ ื”ื›ืœ, ื”ื›ืœ ื”ืชื—ื™ืœ!

ืชื’ื™ื ืขื ืกื˜ื˜ื•ืกื™ ืฆื™ื ื•ืจ ื•ื›ื™ืกื•ื™ ืงื•ื“ ื–ืžื™ื ื™ื ื‘-GitLab ื‘ื”ื’ื“ืจื•ืช ื”-CI/CD ื‘ื’ื•ืฉ ื”ืฆื™ื ื•ืจื•ืช ืฉืœ Gtntral:

ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

ื™ืฆืจืชื™ ืชื’ ืขื ืงื™ืฉื•ืจ ืœืชื™ืขื•ื“ ื‘ืคืœื˜ืคื•ืจืžื” shields.io - ื”ื›ืœ ื“ื™ ืคืฉื•ื˜ ืฉื, ืืชื” ื™ื›ื•ืœ ืœื™ืฆื•ืจ ืชื’ ืžืฉืœืš ื•ืœืงื‘ืœ ืื•ืชื• ื‘ืืžืฆืขื•ืช ื‘ืงืฉื”.

![ะŸั€ะธะผะตั€ ั Shields.io](https://img.shields.io/badge/custom-badge-blue)

ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

Azure DevOps Artifacts ืžืืคืฉืจ ืœืš ื’ื ืœื™ืฆื•ืจ ืชื’ื™ื ืขื‘ื•ืจ ื—ื‘ื™ืœื•ืช ืขื ื”ื’ืจืกื” ื”ืขื“ื›ื ื™ืช ื‘ื™ื•ืชืจ. ืœืฉื ื›ืš, ื‘ืžืงื•ืจ ื‘ืืชืจ Azure DevOps, ืขืœื™ืš ืœืœื—ื•ืฅ ืขืœ Create badge ืขื‘ื•ืจ ื”ื—ื‘ื™ืœื” ืฉื ื‘ื—ืจื” ื•ืœื”ืขืชื™ืง ืืช ืกื™ืžื•ืŸ ื”ืกื™ืžื•ืŸ:

ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

ืžื“ืจื™ืš ืœ-CI/CD ื‘-GitLab ืœืžืชื—ื™ืœื™ื (ื›ืžืขื˜) ืžื•ื—ืœื˜ื™ื

ื”ื•ืกืคืช ื™ื•ืคื™

ื”ื“ื’ืฉืช ืงื˜ืขื™ ืชืฆื•ืจื” ื ืคื•ืฆื™ื

ืชื•ืš ื›ื“ื™ ื›ืชื™ื‘ืช ื”ืชืฆื•ืจื” ื•ื—ื™ืคื•ืฉ ื‘ืชื™ืขื•ื“, ื ืชืงืœืชื™ ื‘ืชื›ื•ื ื” ืžืขื ื™ื™ื ืช ืฉืœ YAML โ€“ ืฉื™ืžื•ืฉ ื—ื•ื–ืจ ื‘ืคืจื’ืžื ื˜ื™ื.

ื›ืคื™ ืฉื ื™ืชืŸ ืœืจืื•ืช ืžื”ื’ื“ืจื•ืช ื”ืžืฉื™ืžื”, ื›ื•ืœืŸ ื“ื•ืจืฉื•ืช ืืช ื”ืชื’ windows ืืฆืœ ื”ืจืฅ, ื•ืžื•ืคืขืœื•ืช ื›ืืฉืจ ื‘ืงืฉืช ืžื™ื–ื•ื’ ื ืฉืœื—ืช ืœืžืืกื˜ืจ/ื ื•ืฆืจ (ืœืžืขื˜ ืชื™ืขื•ื“). ื‘ื•ืื• ื ื•ืกื™ืฃ ืืช ื–ื” ืœืคืจื’ืžื ื˜ ืฉื‘ื• ื ืขืฉื” ืฉื™ืžื•ืฉ ื—ื•ื–ืจ:

.common_tags: &common_tags
  tags:
    - windows
.common_only: &common_only
  only:
    - merge_requests
    - master

ื•ืขื›ืฉื™ื• ืื ื—ื ื• ื™ื›ื•ืœื™ื ืœื”ื›ื ื™ืก ืืช ื”ืคืจื’ืžื ื˜ ืฉื”ื•ื›ืจื– ืงื•ื“ื ืœื›ืŸ ื‘ืชื™ืื•ืจ ื”ืžืฉื™ืžื”:

build job:
  <<: *common_tags
  <<: *common_only

ืฉืžื•ืช ืงื˜ืขื™ื ื—ื™ื™ื‘ื™ื ืœื”ืชื—ื™ืœ ื‘ื ืงื•ื“ื”, ื›ื“ื™ ืœื ืœื”ืชืคืจืฉ ื›ืžืฉื™ืžื”.

ื ื™ื”ื•ืœ ื’ืจืกืื•ืช ืฉืœ ื—ื‘ื™ืœื”

ื‘ืขืช ื™ืฆื™ืจืช ื—ื‘ื™ืœื”, ื”ืžื”ื“ืจ ื‘ื•ื“ืง ืืช ืžืชื’ื™ ืฉื•ืจืช ื”ืคืงื•ื“ื”, ื•ื‘ื”ืขื“ืจื, ืืช ืงื‘ืฆื™ ื”ืคืจื•ื™ืงื˜; ื›ืืฉืจ ื”ื•ื ืžื•ืฆื ืฆื•ืžืช ื’ืจืกื”, ื”ื•ื ืœื•ืงื— ืืช ื”ืขืจืš ืฉืœื• ื›ื’ืจืกื” ืฉืœ ื”ื—ื‘ื™ืœื” ื”ื ื‘ื ื™ืช. ืžืกืชื‘ืจ ืฉื›ื“ื™ ืœื‘ื ื•ืช ื—ื‘ื™ืœื” ืขื ื’ืจืกื” ื—ื“ืฉื”, ืฆืจื™ืš ืœืขื“ื›ืŸ ืื•ืชื” ื‘ืงื•ื‘ืฅ ื”ืคืจื•ื™ืงื˜ ืื• ืœื”ืขื‘ื™ืจ ืื•ืชื” ื›ืืจื’ื•ืžื ื˜ ืฉื•ืจืช ืคืงื•ื“ื”.

ื‘ื•ืื• ื ื•ืกื™ืฃ ืขื•ื“ wishlist ืื—ืช - ืชื ื• ืœืฉื ื™ ื”ืžืกืคืจื™ื ื”ืงื˜ื ื™ื ื‘ื’ืจืกื” ืœื”ื™ื•ืช ื”ืฉื ื” ื•ืชืืจื™ืš ื”ื‘ื ื™ื™ื” ืฉืœ ื”ื—ื‘ื™ืœื”, ื•ื”ื•ืกื™ืคื• ื’ืจืกืื•ืช ืงื“ื-ื”ื•ืฆืื”. ื›ืžื•ื‘ืŸ ืฉื ื™ืชืŸ ืœื”ื•ืกื™ืฃ ืืช ื”ื ืชื•ื ื™ื ื”ืœืœื• ืœืงื•ื‘ืฅ ื”ืคืจื•ื™ืงื˜ ื•ืœื‘ื“ื•ืง ืœืคื ื™ ื›ืœ ื”ื’ืฉื” โ€“ ืื‘ืœ ืืคืฉืจ ื’ื ืœืขืฉื•ืช ื–ืืช ื‘ืฆื ืจืช, ืœืืกื•ืฃ ืืช ื’ืจืกืช ื”ื—ื‘ื™ืœื” ืžื”ื”ืงืฉืจ ื•ืœื”ืขื‘ื™ืจ ืื•ืชื” ื“ืจืš ืืจื’ื•ืžื ื˜ ืฉื•ืจืช ื”ืคืงื•ื“ื”.

ื‘ื•ืื• ื ืกื›ื™ื ืฉืื ื”ื•ื“ืขืช ื”-commit ืžื›ื™ืœื” ืฉื•ืจื” ื›ืžื• release (v./ver./version) <version number> (rev./revision <revision>)?, ืื– ื ื™ืงื— ืืช ื’ืจืกืช ื”ื—ื‘ื™ืœื” ืžื”ืฉื•ืจื” ื”ื–ื•, ื ืฉืœื™ื ืื•ืชื” ืขื ื”ืชืืจื™ืš ื”ื ื•ื›ื—ื™ ื•ื ืขื‘ื™ืจ ืื•ืชื” ื›ืืจื’ื•ืžื ื˜ ืœืคืงื•ื“ื” dotnet pack. ื‘ื”ื™ืขื“ืจ ืชื•ืจ, ืคืฉื•ื˜ ืœื ื ืืกื•ืฃ ืืช ื”ื—ื‘ื™ืœื”.

ื”ืกืงืจื™ืคื˜ ื”ื‘ื ืคื•ืชืจ ืืช ื”ื‘ืขื™ื” ื”ื–ื•:

# ั€ะตะณัƒะปัั€ะฝะพะต ะฒั‹ั€ะฐะถะตะฝะธะต ะดะปั ะฟะพะธัะบะฐ ัั‚ั€ะพะบะธ ั ะฒะตั€ัะธะตะน
$rx = "releases+(v.?|ver.?|version)s*(?<maj>d+)(?<min>.d+)?(?<rel>.d+)?s*((rev.?|revision)?s+(?<rev>[a-zA-Z0-9-_]+))?"
# ะธั‰ะตะผ ัั‚ั€ะพะบัƒ ะฒ ัะพะพะฑั‰ะตะฝะธะธ ะบะพะผะผะธั‚ะฐ, ะฟะตั€ะตะดะฐะฒะฐะตะผะพะผ ะฒ ะพะดะฝะพะน ะธะท ะฟั€ะตะดะพะฟั€ะตะดะตะปัะตะผั‹ั… GitLab'ะพะผ ะฟะตั€ะตะผะตะฝะฝั‹ั…
$found = $env:CI_COMMIT_MESSAGE -match $rx
# ัะพะฒะฟะฐะดะตะฝะธะน ะฝะตั‚ - ะฒั‹ั…ะพะดะธะผ
if (!$found) { Write-Output "no release info found, aborting"; exit }
# ะธะทะฒะปะตะบะฐะตะผ ะผะฐะถะพั€ะฝัƒัŽ ะธ ะผะธะฝะพั€ะฝัƒัŽ ะฒะตั€ัะธะธ
$maj = $matches['maj']
$min = $matches['min']
# ะตัะปะธ ัั‚ั€ะพะบะฐ ัะพะดะตั€ะถะธั‚ ะฝะพะผะตั€ ั€ะตะปะธะทะฐ - ะธัะฟะพะปัŒะทัƒะตะผ ะตะณะพ, ะธะฝะฐั‡ะต - ั‚ะตะบัƒั‰ะธะน ะณะพะด
if ($matches.ContainsKey('rel')) { $rel = $matches['rel'] } else { $rel = ".$(get-date -format "yyyy")" }
# ะฒ ะบะฐั‡ะตัั‚ะฒะต ะฝะพะผะตั€ะฐ ัะฑะพั€ะบะธ - ั‚ะตะบัƒั‰ะธะต ะผะตััั† ะธ ะดะตะฝัŒ
$bld = $(get-date -format "MMdd")
# ะตัะปะธ ะตัั‚ัŒ ะดะฐะฝะฝั‹ะต ะฟะพ ะฟั€ะตั€ะตะปะธะทะฝะพะน ะฒะตั€ัะธะธ - ะฒะบะปัŽั‡ะฐะตะผ ะธั… ะฒ ะฒะตั€ัะธัŽ
if ($matches.ContainsKey('rev')) { $rev = "-$($matches['rev'])" } else { $rev = '' }
# ัะพะฑะธั€ะฐะตะผ ะตะดะธะฝัƒัŽ ัั‚ั€ะพะบัƒ ะฒะตั€ัะธะธ
$version = "$maj$min$rel.$bld$rev"
# ัะพะฑะธั€ะฐะตะผ ะฟะฐะบะตั‚ั‹
dotnet pack -c Release -o . /p:Version=$version

ื”ื•ืกืคืช ืกืงืจื™ืคื˜ ืœืžืฉื™ืžื” pack and deploy job ื•ืœืฆืคื•ืช ื‘ื”ืจื›ื‘ืช ื”ื—ื‘ื™ืœื•ืช ืืš ื•ืจืง ื‘ื ื•ื›ื—ื•ืช ืžื—ืจื•ื–ืช ื ืชื•ื ื” ื‘ื”ื•ื“ืขืช ื”-commit.

ื‘ืกืš ื”ื›ืœ

ืœืื—ืจ ืฉื‘ื–ื‘ื–ื ื• ื›ื—ืฆื™ ืฉืขื” ืื• ืฉืขื” ื‘ื›ืชื™ื‘ืช ื”ืชืฆื•ืจื”, ื ื™ืคื•ื™ ื‘ืื’ื™ื ื‘-powershell ื”ืžืงื•ืžื™ ื•ืื•ืœื™, ื›ืžื” ื”ืฉืงื•ืช ืœื ืžื•ืฆืœื—ื•ืช, ืงื™ื‘ืœื ื• ืชืฆื•ืจื” ืคืฉื•ื˜ื” ืœืื•ื˜ื•ืžืฆื™ื” ืฉืœ ืžืฉื™ืžื•ืช ืฉื’ืจืชื™ื•ืช.

ื›ืžื•ื‘ืŸ, GitLab CI / CD ื”ื•ื ื”ืจื‘ื” ื™ื•ืชืจ ื ืจื—ื‘ ื•ืจื‘-ื’ื•ื ื™ ืžืžื” ืฉื”ื•ื ืขืฉื•ื™ ืœื”ื™ืจืื•ืช ืœืื—ืจ ืงืจื™ืืช ื”ืžื“ืจื™ืš ื”ื–ื” - ื–ื” ืœื ื ื›ื•ืŸ ื‘ื›ืœืœ. ืฉื ืืคื™ืœื• Auto DevOps ื”ื•ืืžึฐืึทืคืฉืึถืจ

ืœื–ื”ื•ืช, ืœื‘ื ื•ืช, ืœื‘ื“ื•ืง, ืœืคืจื•ืก ื•ืœื ื˜ืจ ืืช ื”ื™ื™ืฉื•ืžื™ื ืฉืœืš ื‘ืื•ืคืŸ ืื•ื˜ื•ืžื˜ื™

ื›ืขืช ื”ืชื•ื›ื ื™ื•ืช ื”ืŸ ืœื”ื’ื“ื™ืจ ืฆื™ื ื•ืจ ืœืคืจื™ืกืช ื™ื™ืฉื•ืžื™ื ืœ-Azure, ื‘ืืžืฆืขื•ืช Pulumi ื•ืงื‘ื™ืขื” ืื•ื˜ื•ืžื˜ื™ืช ืฉืœ ืกื‘ื™ื‘ืช ื”ื™ืขื“, ืืฉืจ ื™ืกื•ืงืจ ื‘ืžืืžืจ ื”ื‘ื.

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”