αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

αž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž˜αŸ’αžšαž»αž„αž‘αž»αž€αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αž’αž—αž·αžœαžŒαŸ’αžαž“αŸ java αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžšαž”αŸ„αŸ‡αž•αŸ’αžŸαžΆαž™αž•αž›αž·αžαž•αž›αžšαž”αžŸαŸ‹αž–αž½αž€αž‚αŸαž™αŸ‰αžΆαž„αž†αžΆαž”αŸ‹αžšαž αŸαžŸαž‘αŸ…αž€αžΆαž“αŸ‹ sonatype αž“αž·αž„/ឬ maven αžƒαŸ’αž›αžΆαŸ†αž„αž€αžŽαŸ’αžαžΆαž›αžŠαŸ„αž™αž”αŸ’αžšαžΎ GitLab αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡ αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž“αž·αž™αžΆαž™αž’αŸ†αž–αžΈαž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ gitlab-runner, gitlab-ci αž“αž·αž„ maven-plugin αžŠαžΎαž˜αŸ’αž”αžΈαžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž”αž‰αŸ’αž αžΆαž“αŸαŸ‡αŸ”

αžαž˜αŸ’αžšαžΌαžœαž€αžΆαžšαž‡αžΆαž˜αž»αž“αŸ–

  • αž€αžΆαžšαž•αŸ’αž‘αž»αž€αžŸαŸ„αžš mvn αž“αž·αž„ GPG αž”αŸ’αžšαž€αž”αžŠαŸ„αž™αžŸαž»αžœαžαŸ’αžαž·αž—αžΆαž–αŸ”
  • αž’αžΆαž“αžΆαž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž—αžΆαžšαž€αž·αž…αŸ’αž… CI αžŸαžΆαž’αžΆαžšαžŽαŸˆαŸ”
  • αž€αŸ†αž–αž»αž„αž”αž„αŸ’αž αŸ„αŸ‡αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽ (αž€αžΆαžšαž…αŸαž‰αž•αŸ’αžŸαžΆαž™/αžšαžΌαž”αžαž) αž‘αŸ…αžƒαŸ’αž›αžΆαŸ†αž„αžŸαžΆαž’αžΆαžšαžŽαŸˆαŸ”
  • αž€αžΆαžšαžαŸ’αžšαž½αžαž–αž·αž“αž·αžαŸ’αž™αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αž“αŸƒαž€αŸ†αžŽαŸ‚αž…αŸαž‰αž•αŸ’αžŸαžΆαž™αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž•αŸ’αžŸαžΆαž™αž“αŸ…αž€αŸ’αž“αž»αž„ maven Central αŸ”
  • αžŠαŸ†αžŽαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž‘αžΌαž‘αŸ…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž•αŸ’αž‘αž»αž€αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽαž‘αŸ…αž€αŸ’αž“αž»αž„αžƒαŸ’αž›αžΆαŸ†αž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„αž‡αžΆαž…αŸ’αžšαžΎαž“αŸ”
  • αž—αžΆαž–αžŸαžΆαž˜αž‰αŸ’αž‰ αž“αž·αž„αž—αžΆαž–αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž“αŸƒαž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αŸ”

αž˜αžΆαžαž·αž€αžΆ

αž–αŸαžαŸŒαž˜αžΆαž“αž‘αžΌαž‘αŸ…

  • αž€αžΆαžšαž–αž·αž–αžŽαŸŒαž“αžΆαž›αž˜αŸ’αž’αž·αžαž“αŸƒαž™αž“αŸ’αžαž€αžΆαžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αŸ„αŸ‡αž•αŸ’αžŸαžΆαž™αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽαž‘αŸ… Maven Central αžαžΆαž˜αžšαž™αŸˆαžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αž”αž„αŸ’αž αŸ„αŸ‡ Sonatype OSS αžαŸ’αžšαžΌαžœαž”αžΆαž“αž–αž·αž–αžŽαŸŒαž“αžΆαžšαž½αž…αž αžΎαž™αž“αŸ…αž€αŸ’αž“αž»αž„ αž’αžαŸ’αžαž”αž‘β€‹αž“αŸαŸ‡ αž’αŸ’αž“αž€β€‹αž”αŸ’αžšαžΎ GoogolplexαžŠαžΌαž…αŸ’αž“αŸαŸ‡αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž™αŸ„αž„αž‘αŸ…αž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡αž“αŸ…αž€αž“αŸ’αž›αŸ‚αž„αžŠαŸ‚αž›αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœαŸ”
  • αž…αž»αŸ‡αžˆαŸ’αž˜αŸ„αŸ‡αž‡αžΆαž˜αž»αž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ Sonatype JIRA αž αžΎαž™αž”αžΎαž€αžŸαŸ†αž”αž»αžαŸ’αžšαžŠαžΎαž˜αŸ’αž”αžΈαž”αžΎαž€αžƒαŸ’αž›αžΆαŸ†αž„ (αž’αžΆαž“αž•αŸ’αž“αŸ‚αž€αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž–αŸαžαŸŒαž˜αžΆαž“αž›αž˜αŸ’αž’αž·αžαž”αž“αŸ’αžαŸ‚αž˜ αž”αž„αŸ’αž€αžΎαžαžŸαŸ†αž”αž»αžαŸ’αžš Sonatype JIRA) αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž”αžΎαž€αžƒαŸ’αž›αžΆαŸ†αž„ αž‚αžΌαž…αžΌαž›/αž–αžΆαž€αŸ’αž™αžŸαž˜αŸ’αž„αžΆαžαŸ‹ JIRA (αžαž‘αŸ…αž“αŸαŸ‡αž αŸ…αžαžΆαž‚αžŽαž“αžΈ Sonatype) αž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎαžŠαžΎαž˜αŸ’αž”αžΈαž•αŸ’αž‘αž»αž€αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽαž‘αŸ…αž€αžΆαž“αŸ‹ Sonatype nexus αŸ”
  • αž›αžΎαžŸαž–αžΈαž“αŸαŸ‡ αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž“αŸƒαž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž€αžΌαž“αžŸαŸ„ GPG αžαŸ’αžšαžΌαžœαž”αžΆαž“αž–αž·αž–αžŽαŸŒαž“αžΆαž™αŸ‰αžΆαž„αžŸαŸ’αž„αž½αžαŸ” αžŸαžΌαž˜αž˜αžΎαž›αž•αŸ’αž“αŸ‚αž€αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž–αŸαžαŸŒαž˜αžΆαž“αž›αž˜αŸ’αž’αž·αžαž”αž“αŸ’αžαŸ‚αž˜αŸ” αž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’ GnuPG αžŠαžΎαž˜αŸ’αž”αžΈαž…αž»αŸ‡αž αžαŸ’αžαž›αŸαžαžΆαž›αžΎαžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽ
  • αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž€αž»αž„αžŸαžΌαž›αž›αžΈαž“αž»αž…αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž€αžΎαžαž€αžΌαž“αžŸαŸ„ GPG (gnupg/gnupg2) αž“αŸ„αŸ‡αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαžŠαŸ†αž‘αžΎαž„ rng- αž§αž”αž€αžšαžŽαŸ αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž€αžΎαž entropy αŸ” αž”αžΎαž˜αž·αž“αžŠαžΌαž…αŸ’αž“αŸ„αŸ‡αž‘αŸ αž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž€αžΌαž“αžŸαŸ„αž’αžΆαž…αž…αŸ†αžŽαžΆαž™αž–αŸαž›αž™αžΌαžšαžŽαžΆαžŸαŸ‹αŸ”
  • αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αž•αŸ’αž‘αž»αž€ αžŸαžΆαž’αžΆαžšαžŽαŸˆ αž‚αŸ’αžšαžΆαž”αŸ‹αž…αž»αž… GPG

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„αž‚αž˜αŸ’αžšαŸ„αž„αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αž“αŸ…αž€αŸ’αž“αž»αž„ GitLab

  • αžŠαŸ†αž”αžΌαž„αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž”αž„αŸ’αž€αžΎαž αž“αž·αž„αž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž‚αž˜αŸ’αžšαŸ„αž„αžŠαŸ‚αž›αž”αŸ†αž–αž„αŸ‹αž”αž„αŸ’αž αžΌαžšαž”αŸ’αžšαŸαž„αž“αžΉαž„αžαŸ’αžšαžΌαžœαžšαž€αŸ’αžŸαžΆαž‘αž»αž€αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽαŸ” αžαŸ’αž‰αž»αŸ†αž”αžΆαž“αž αŸ…αž‚αž˜αŸ’αžšαŸ„αž„αžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†αž™αŸ‰αžΆαž„αžŸαžΆαž˜αž‰αŸ’αž‰ αž“αž·αž„αž˜αž·αž“αžŸαŸ’αž˜αž»αž‚αžŸαŸ’αž˜αžΆαž‰ - αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™
  • αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž”αž„αŸ’αž€αžΎαžαžƒαŸ’αž›αžΆαŸ†αž„ αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαžŠαžΆαž€αŸ‹αž€αž˜αŸ’αžšαž·αžαž€αžΆαžšαž…αžΌαž›αž”αŸ’αžšαžΎ αžŠαžΎαž˜αŸ’αž”αžΈαž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαžƒαŸ’αž›αžΆαŸ†αž„αŸ”
    αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ -> αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹ -> αžƒαŸ’αž›αžΆαŸ†αž„ -> αžŸαžΆαžαžΆαž€αžΆαžšαž–αžΆαžšαŸ” αž™αžΎαž„αž›αž»αž”αž…αŸ’αž”αžΆαž”αŸ‹αž‘αžΆαŸ†αž„αž’αžŸαŸ‹ αž αžΎαž™αž”αž“αŸ’αžαŸ‚αž˜αž…αŸ’αž”αžΆαž”αŸ‹αžαŸ‚αž˜αž½αž™αž‡αžΆαž˜αž½αž™ Wildcard * αžŠαŸ‚αž›αž˜αžΆαž“αžŸαž·αž‘αŸ’αž’αž·αžšαž»αž‰ αž“αž·αž„αž”αž‰αŸ’αž…αžΌαž›αž…αžΌαž›αž‚αŸ’αž“αžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαŸ‚αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αžŠαŸ‚αž›αž˜αžΆαž“αžαž½αž“αžΆαž‘αžΈαž‡αžΆαž’αŸ’αž“αž€αžαŸ‚αž‘αžΆαŸ†αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡αŸ” αž…αŸ’αž”αžΆαž”αŸ‹αž“αŸαŸ‡αž“αžΉαž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸƒαž‚αž˜αŸ’αžšαŸ„αž„αž“αŸαŸ‡ αž“αž·αž„αž€αŸ’αžšαž»αž˜αžŠαŸ‚αž›αž‚αž˜αŸ’αžšαŸ„αž„αž“αŸαŸ‡αž‡αžΆαž€αž˜αŸ’αž˜αžŸαž·αž‘αŸ’αž’αž·αŸ”
    αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central
  • αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“αž’αŸ’αž“αž€αžαŸ‚αž‘αžΆαŸ†αž…αŸ’αžšαžΎαž“αž“αžΆαž€αŸ‹αž“αŸ„αŸ‡ αžŠαŸ†αžŽαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αžŠαŸαž›αŸ’αž’αž”αŸ†αž•αž»αžαž‚αžΊαžαŸ’αžšαžΌαžœαž€αŸ†αžŽαžαŸ‹αž€αžΆαžšαž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„αž‡αžΆαž‚αŸ„αž›αž€αžΆαžšαžŽαŸαŸ”
    αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ -> αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹ -> αž‘αžΌαž‘αŸ… -> αž—αžΆαž–αž˜αžΎαž›αžƒαžΎαž‰ αž›αž€αŸ’αžαžŽαŸˆαž–αž·αžŸαŸαžŸαž‚αž˜αŸ’αžšαŸ„αž„ αž€αžΆαžšαž’αž“αž»αž‰αŸ’αž‰αžΆαž αž αžΎαž™αž€αŸ†αžŽαžαŸ‹αž›αž‘αŸ’αž’αž—αžΆαž–αž˜αžΎαž›αžƒαžΎαž‰αž‚αž˜αŸ’αžšαŸ„αž„αž‘αŸ… αž―αž€αž‡αž“.
    αžαŸ’αž‰αž»αŸ†αž˜αžΆαž“αž‚αž˜αŸ’αžšαŸ„αž„αžŠαŸ‚αž›αž’αžΆαž…αž…αžΌαž›αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž”αžΆαž“αž‡αžΆαžŸαžΆαž’αžΆαžšαžŽαŸˆ αžŠαŸ„αž™αžŸαžΆαžšαžαŸ’αž‰αž»αŸ†αž”αŸ’αžšαžΎ GitLab Runner αž•αŸ’αž‘αžΆαž›αŸ‹αžαŸ’αž›αž½αž“αžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ† αž αžΎαž™αž˜αžΆαž“αžαŸ‚αžαŸ’αž‰αž»αŸ†αž‘αŸαžŠαŸ‚αž›αž’αžΆαž…αž…αžΌαž›αž”αŸ’αžšαžΎαžŠαžΎαž˜αŸ’αž”αžΈαž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαžƒαŸ’αž›αžΆαŸ†αž„αŸ” αžαžΆαž˜αž–αž·αžαž‘αŸ… αžœαžΆαž˜αž·αž“αž˜αŸ‚αž“αž‡αžΆαž•αž›αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†αž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αž„αŸ’αž αžΆαž‰αž–αŸαžαŸŒαž˜αžΆαž“αž―αž€αž‡αž“αž“αŸ…αž€αŸ’αž“αž»αž„αž€αŸ†αžŽαžαŸ‹αž αŸαžαž»αž”αŸ†αž–αž„αŸ‹αž”αž„αŸ’αž αžΌαžšαž”αŸ’αžšαŸαž„αžŸαžΆαž’αžΆαžšαžŽαŸˆαž‘αŸαŸ”
  • αžšαžΉαžαž”αž“αŸ’αžαžΉαž„αž…αŸ’αž”αžΆαž”αŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαžƒαŸ’αž›αžΆαŸ†αž„
    αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ -> αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹ -> αžƒαŸ’αž›αžΆαŸ†αž„ -> Push Rules αž αžΎαž™αž€αŸ†αžŽαžαŸ‹ Committer restriction αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αžαžΆαžαžΎαž’αŸ’αž“αž€αž“αž·αž–αž“αŸ’αž’αž‚αžΊαž‡αžΆαž‘αž„αŸ‹αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ GitLab αžŠαŸ‚αžšαž¬αž‘αŸαŸ” αžαŸ’αž‰αž»αŸ†αž€αŸαžŸαžΌαž˜αž•αŸ’αžαž›αŸ‹αž’αž“αž»αžŸαžΆαžŸαž“αŸαž±αŸ’αž™αž€αŸ†αžŽαžαŸ‹ αž”αŸ’αžαŸαž‡αŸ’αž‰αžΆαž…αž»αŸ‡αž αžαŸ’αžαž›αŸαžαžΆαž αžΎαž™αž€αŸ†αžŽαžαŸ‹αž‘αž„αŸ‹ Reject unsigned commitsαŸ”
  • αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž‚αž“αŸ’αž›αžΉαŸ‡αžŠαžΎαž˜αŸ’αž”αžΈαžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž—αžΆαžšαž€αž·αž…αŸ’αž…
    αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ -> αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹ -> CI / CD -> Pipeline triggers αž αžΎαž™αž”αž„αŸ’αž€αžΎαžαžŸαž‰αŸ’αž‰αžΆ trigger-token αžαŸ’αž˜αžΈ
    αžŸαž‰αŸ’αž‰αžΆαžŸαž˜αŸ’αž„αžΆαžαŸ‹αž“αŸαŸ‡αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž“αŸ’αžαŸ‚αž˜αž—αŸ’αž›αžΆαž˜αŸ—αž‘αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž‘αžΌαž‘αŸ…αž“αŸƒαž’αžαŸαžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αŸ’αžšαž»αž˜αž‚αž˜αŸ’αžšαŸ„αž„αŸ”
    αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž€αŸ’αžšαž»αž˜ -> αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹ -> CI / CD -> Variables αž αžΎαž™αž”αž“αŸ’αžαŸ‚αž˜αž’αžαŸαžšαž˜αž½αž™αŸ” DEPLOY_TOKEN αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžαž˜αŸ’αž›αŸƒαžŸαž‰αŸ’αž‰αžΆαž€αŸαŸ‡αŸ”

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž’αŸ’αž“αž€αžšαžαŸ‹ GitLab

αž•αŸ’αž“αŸ‚αž€αž“αŸαŸ‡αž–αž·αž–αžŽαŸŒαž“αžΆαž’αŸ†αž–αžΈαž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž—αžΆαžšαž€αž·αž…αŸ’αž…αž›αžΎαž€αžΆαžšαžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αžŠαŸ„αž™αž”αŸ’αžšαžΎαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαžαŸ‹αž•αŸ’αž‘αžΆαž›αŸ‹αžαŸ’αž›αž½αž“αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€ (αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹) αž“αž·αž„αžŸαžΆαž’αžΆαžšαžŽαŸˆ (αž…αŸ‚αž€αžšαŸ†αž›αŸ‚αž€)αŸ”

αž’αŸ’αž“αž€αžšαžαŸ‹αž”αŸ’αžšαžŽαžΆαŸ†αž„αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹

αžαŸ’αž‰αž»αŸ†β€‹αž”αŸ’αžšαžΎβ€‹αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“β€‹αžšαžαŸ‹β€‹αž•αŸ’αž‘αžΆαž›αŸ‹β€‹αžαŸ’αž›αž½αž“β€‹αž–αŸ’αžšαŸ„αŸ‡β€‹αž‡αžΆβ€‹αžŠαŸ†αž”αžΌαž„β€‹αžœαžΆβ€‹αž„αžΆαž™β€‹αžŸαŸ’αžšαž½αž› αž›αžΏαž“ αžαŸ„αž€αŸ”
αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αžšαžαŸ‹αžαŸ’αž‰αž»αŸ†αžŸαžΌαž˜αžŽαŸ‚αž“αžΆαŸ† Linux VDS αžŠαŸ‚αž›αž˜αžΆαž“ CPU 1, RAM 2 GB, HDD 20 GB αŸ” αžαž˜αŸ’αž›αŸƒαž…αŸαž‰ ~ 3000β‚½ αž€αŸ’αž“αž»αž„αž˜αž½αž™αž†αŸ’αž“αžΆαŸ†αŸ”

αž’αŸ’αž“αž€αžšαžαŸ‹αžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†

αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αžšαžαŸ‹αžαŸ’αž‰αž»αŸ†αž™αž€ VDS 4 CPU, RAM 4 GB, 50 GB SSD αŸ” αžœαžΆαž˜αžΆαž“αžαž˜αŸ’αž›αŸƒ ~ 11000β‚½ αž αžΎαž™αž˜αž·αž“αžŠαŸ‚αž›αžŸαŸ„αž€αžŸαŸ’αžαžΆαž™αžœαžΆαŸ”
αžαŸ’αž‰αž»αŸ†αž˜αžΆαž“αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αžŸαžšαž»αž” ៧ αž‚αŸ’αžšαžΏαž„αŸ” 7 αž“αŸ…αž›αžΎ aruba αž“αž·αž„ 5 αž“αŸ…αž›αžΎ ihor αŸ”

αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž™αžΎαž„αž˜αžΆαž“αž’αŸ’αž“αž€αžšαžαŸ‹αž”αŸ’αžšαžŽαžΆαŸ†αž„αŸ” αž₯αž‘αžΌαžœαž“αŸαŸ‡αž™αžΎαž„αž“αžΉαž„αžšαŸ€αž”αž…αŸ†αžœαžΆαŸ”
αž™αžΎαž„αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αžαžΆαž˜αžšαž™αŸˆ SSH αž αžΎαž™αžŠαŸ†αž‘αžΎαž„ java, git, maven, gnupg2 αŸ”

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαžαŸ‹ gitlab

  • αž”αž„αŸ’αž€αžΎαžαž€αŸ’αžšαž»αž˜αžαŸ’αž˜αžΈαŸ” runner
    sudo groupadd runner
  • αž”αž„αŸ’αž€αžΎαžαžαžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžƒαŸ’αž›αžΆαŸ†αž„αžŸαž˜αŸ’αž„αžΆαžαŸ‹ maven αž“αž·αž„αž€αŸ†αžŽαžαŸ‹αžŸαž·αž‘αŸ’αž’αž·αž€αŸ’αžšαž»αž˜ runner
    αž’αŸ’αž“αž€αž’αžΆαž…αžšαŸ†αž›αž„αž‡αŸ†αž αžΆαž“αž“αŸαŸ‡ αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž˜αž·αž“αž˜αžΆαž“αž‚αž˜αŸ’αžšαŸ„αž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž’αŸ’αž“αž€αžšαžαŸ‹αž…αŸ’αžšαžΎαž“αž“αŸ…αž›αžΎαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αžαŸ‚αž˜αž½αž™αŸ”

    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • αž”αž„αŸ’αž€αžΎαžαž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ gitlab-deployer αž αžΎαž™αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ…αž€αŸ’αžšαž»αž˜ runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ…αž―αž€αžŸαžΆαžš /etc/ssh/sshd_config αž”αž“αŸ’αž‘αžΆαžαŸ‹αž”αž“αŸ’αž‘αžΆαž”αŸ‹
    AllowUsers root@* [email protected]
  • αž…αžΆαž”αŸ‹αž•αŸ’αžŠαžΎαž˜αž‘αžΎαž„αžœαž·αž‰ sshd
    systemctl restart sshd
  • αž€αŸ†αžŽαžαŸ‹αž–αžΆαž€αŸ’αž™αžŸαž˜αŸ’αž„αžΆαžαŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ gitlab-deployer (αžœαžΆβ€‹αž’αžΆαž…β€‹αž‡αžΆβ€‹αžšαžΏαž„β€‹αžŸαžΆαž˜αž‰αŸ’αž‰ αžŠαŸ„αž™β€‹αžŸαžΆαžšβ€‹αžαŸ‚β€‹αž˜αžΆαž“β€‹αž€αžΆαžšβ€‹αžŠαžΆαž€αŸ‹β€‹αž€αž˜αŸ’αžšαž·αžβ€‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ localhost)
    passwd gitlab-deployer
  • αžŠαŸ†αž‘αžΎαž„ GitLab Runner (Linux x86-64)
    sudo wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
    sudo chmod +x /usr/local/bin/gitlab-runner
    ln -s /usr/local/bin/gitlab-runner /etc/alternatives/gitlab-runner
    ln -s /etc/alternatives/gitlab-runner /usr/bin/gitlab-runner
  • αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž‚αŸαž αž‘αŸ†αž–αŸαžš gitlab.com -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners αž αžΎαž™αž…αž˜αŸ’αž›αž„αž“αž·αž˜αž·αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαž…αž»αŸ‡αžˆαŸ’αž˜αŸ„αŸ‡

αž’αŸαž€αŸ’αžšαž„αŸ‹

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

  • αž€αžΆαžšαž…αž»αŸ‡αžˆαŸ’αž˜αŸ„αŸ‡αž’αŸ’αž“αž€αžšαžαŸ‹αž”αŸ’αžšαžŽαžΆαŸ†αž„
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

αžŠαŸ†αžŽαžΎαžšαž€αžΆαžš

Runtime platform arch=amd64 os=linux pid=17594 revision=3001a600 version=11.10.0
Running in system-mode.
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://gitlab.com/
Please enter the gitlab-ci token for this runner:
REGISTRATION_TOKEN
Please enter the gitlab-ci description for this runner:
[ih1174328.vds.myihor.ru]: Deploy Runner
Please enter the gitlab-ci tags for this runner (comma separated):
deploy
Registering runner... succeeded                     runner=ZvKdjJhx
Please enter the executor: docker-ssh, parallels, virtualbox, docker-ssh+machine, kubernetes, docker, ssh, docker+machine, shell:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

  • αž™αžΎαž„αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αžαžΆαž’αŸ’αž“αž€αžšαžαŸ‹αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αž»αŸ‡αžˆαŸ’αž˜αŸ„αŸ‡αŸ” αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž‚αŸαž αž‘αŸ†αž–αŸαžš gitlab.com -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners -> Runners αžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αŸ’αžœαžΎαž±αŸ’αž™αžŸαž€αž˜αŸ’αž˜αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„αž“αŸαŸ‡

αž’αŸαž€αŸ’αžšαž„αŸ‹

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

  • αž”αž“αŸ’αžαŸ‚αž˜ αžŠαžΆαž…αŸ‹αžŠαŸ„αž™αž‘αŸ‚αž€ αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜ /etc/systemd/system/gitlab-deployer.service
    [Unit]
    Description=GitLab Deploy Runner
    After=syslog.target network.target
    ConditionFileIsExecutable=/usr/local/bin/gitlab-runner
    [Service]
    StartLimitInterval=5
    StartLimitBurst=10
    ExecStart=/usr/local/bin/gitlab-runner "run" "--working-directory" "/home/gitlab-deployer" "--config" "/etc/gitlab-runner/gitlab-deployer-config.toml" "--service" "gitlab-deployer" "--syslog" "--user" "gitlab-deployer"
    Restart=always
    RestartSec=120
    [Install]
    WantedBy=multi-user.target
  • αž™αžΎαž„αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αŸ”
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • αž™αžΎαž„αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αžαžΆαž’αŸ’αž“αž€αžšαžαŸ‹αž”αŸ’αžšαžŽαžΆαŸ†αž„αž€αŸ†αž–αž»αž„αžšαžαŸ‹αŸ”

αž§αž‘αžΆαž αžšαžŽαŸ:

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž‚αž“αŸ’αž›αžΉαŸ‡ GPG

  • αž–αžΈαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αžŠαžΌαž…αž‚αŸ’αž“αžΆαž™αžΎαž„αž‘αŸ…αžαžΆαž˜αžšαž™αŸˆ ssh αž“αŸ…αž€αŸ’αžšαŸ„αž˜αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ gitlab-deployer (αž“αŸαŸ‡αž˜αžΆαž“αžŸαžΆαžšαŸˆαžŸαŸ†αžαžΆαž“αŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž€αžΌαž“αžŸαŸ„ GPG)

    ssh [email protected]

  • αž™αžΎαž„αž”αž„αŸ’αž€αžΎαžαž€αžΌαž“αžŸαŸ„αžŠαŸ„αž™αž†αŸ’αž›αžΎαž™αžŸαŸ†αžŽαž½αžšαŸ” αžαŸ’αž‰αž»αŸ†αž”αžΆαž“αž”αŸ’αžšαžΎαžˆαŸ’αž˜αŸ„αŸ‡ αž“αž·αž„αž’αŸŠαžΈαž˜αŸ‚αž›αž•αŸ’αž‘αžΆαž›αŸ‹αžαŸ’αž›αž½αž“αžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†αŸ”
    αžαŸ’αžšαžΌαžœαž”αŸ’αžšαžΆαž€αžŠαžαžΆαž”αž‰αŸ’αž‡αžΆαž€αŸ‹αž–αžΆαž€αŸ’αž™αžŸαž˜αŸ’αž„αžΆαžαŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ„αŸ” αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽαž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αž»αŸ‡αž αžαŸ’αžαž›αŸαžαžΆαžŠαŸ„αž™αž”αŸ’αžšαžΎαžŸαŸ„αž“αŸαŸ‡αŸ”

    gpg --gen-key 

  • αž–αž·αž“αž·αžαŸ’αž™

    gpg --list-keys -a
    /home/gitlab-deployer/.gnupg/pubring.gpg
    ----------------------------------------
    pub   4096R/00000000 2019-04-19
    uid                  Petruha Petrov <[email protected]>
    sub   4096R/11111111 2019-04-19

  • αž€αŸ†αž–αž»αž„αž”αž„αŸ’αž αŸ„αŸ‡αžŸαŸ„αžŸαžΆαž’αžΆαžšαžŽαŸˆαžšαž”αžŸαŸ‹αž™αžΎαž„αž‘αŸ…αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸ

    gpg --keyserver keys.gnupg.net --send-key 00000000
    gpg: sending key 00000000 to hkp server keys.gnupg.net

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ Maven

  • αž…αžΌαž›αž‡αžΆαž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ gitlab-deployer
    su gitlab-deployer 
  • αž”αž„αŸ’αž€αžΎαžαž”αž‰αŸ’αž‡αžΈαžˆαŸ’αž˜αŸ„αŸ‡ maven αžƒαŸ’αž›αžΆαŸ†αž„ αž αžΎαž™αž—αŸ’αž‡αžΆαž”αŸ‹αž‘αŸ…αžƒαŸ’αž›αžΆαŸ†αž„αžŸαž˜αŸ’αž„αžΆαžαŸ‹ (αž€αž»αŸ†αž˜αžΆαž“αž€αŸ†αž αž»αžŸ)
    αž‡αŸ†αž αžΆαž“αž“αŸαŸ‡αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αžšαŸ†αž›αž„αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž˜αž·αž“αž˜αžΆαž“αž‚αž˜αŸ’αžšαŸ„αž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž’αŸ’αž“αž€αžšαžαŸ‹αž‡αžΆαž…αŸ’αžšαžΎαž“αž“αŸ…αž›αžΎαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αžαŸ‚αž˜αž½αž™αŸ”

    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • αž”αž„αŸ’αž€αžΎαžαžŸαŸ„αž˜αŸ
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • αž”αž„αŸ’αž€αžΎαžαž―αž€αžŸαžΆαžš ~/.m2/settings-security.xml
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • αž€αžΆαžšαž’αŸŠαž·αž“αž‚αŸ’αžšαžΈαž”αž–αžΆαž€αŸ’αž™αžŸαž˜αŸ’αž„αžΆαžαŸ‹αž–αžΈαž‚αžŽαž“αžΈ Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • αž”αž„αŸ’αž€αžΎαžαž―αž€αžŸαžΆαžš ~/.m2/settings.xml
    <settings>  
    <profiles>
        <profile>
            <id>env</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <gpg.passphrase>GPG_SECRET_KEY_PASSPHRASE</gpg.passphrase>
            </properties>
        </profile>
    </profiles>
    <servers>
        <server>
            <id>sonatype</id>
            <username>SONATYPE_USERNAME</username>
            <password>{98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}</password>
        </server>
    </servers>
    </settings>

αž€αž“αŸ’αž›αŸ‚αž„αžŽαžΆ
GPG_SECRET_KEY_PASSHRASE - αž–αžΆαž€αŸ’αž™αžŸαž˜αŸ’αž„αžΆαžαŸ‹αžŸαŸ„ GPG
SONATYPE_USERNAME - αž…αžΌαž›αž‚αžŽαž“αžΈ sonatype

αžœαžΆαž”αž‰αŸ’αž…αž”αŸ‹αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„αž’αŸ’αž“αž€αžšαžαŸ‹αž€αžΆαžš αž’αŸ’αž“αž€αž’αžΆαž…αž”αž“αŸ’αžαž‘αŸ…αž•αŸ’αž“αŸ‚αž€ GitLab αžŸαŸŠαžΈαž’αžΆαž™

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž”αžΆαž“αž…αŸ‚αž€αžšαŸ†αž›αŸ‚αž€ αž€αžΆαžšαž”αŸ’αžšαž€αžΆαžŸ αžšαž”αžŸαŸ‹ Runner

αž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž‚αž“αŸ’αž›αžΉαŸ‡ GPG

  • αžŠαŸ†αž”αžΌαž„αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž”αž„αŸ’αž€αžΎαžαž€αžΌαž“αžŸαŸ„ GPG αŸ” αžŠαžΎαž˜αŸ’αž”αžΈαž’αŸ’αžœαžΎαžŠαžΌαž…αž“αŸαŸ‡αžŠαŸ†αž‘αžΎαž„ gnupg αŸ”

    yum install -y gnupg

  • αž™αžΎαž„αž”αž„αŸ’αž€αžΎαžαž€αžΌαž“αžŸαŸ„αžŠαŸ„αž™αž†αŸ’αž›αžΎαž™αžŸαŸ†αžŽαž½αžšαŸ” αžαŸ’αž‰αž»αŸ†αž”αžΆαž“αž”αŸ’αžšαžΎαžˆαŸ’αž˜αŸ„αŸ‡ αž“αž·αž„αž’αŸŠαžΈαž˜αŸ‚αž›αž•αŸ’αž‘αžΆαž›αŸ‹αžαŸ’αž›αž½αž“αžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†αŸ” αžαŸ’αžšαžΌαžœαž”αŸ’αžšαžΆαž€αžŠαžαžΆαž”αž‰αŸ’αž‡αžΆαž€αŸ‹αž–αžΆαž€αŸ’αž™αžŸαž˜αŸ’αž„αžΆαžαŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ„αŸ”

    gpg --gen-key 

  • αž‘αžΆαž‰αž™αž€αž–αŸαžαŸŒαž˜αžΆαž“αžŸαŸ†αžαžΆαž“αŸ‹αŸ—

    gpg --list-keys -a
    pub   rsa3072 2019-04-24 [SC] [expires: 2021-04-23]
      2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    uid           [ultimate] tttemp <[email protected]>
    sub   rsa3072 2019-04-24 [E] [expires: none]

  • αž€αŸ†αž–αž»αž„αž”αž„αŸ’αž αŸ„αŸ‡αžŸαŸ„αžŸαžΆαž’αžΆαžšαžŽαŸˆαžšαž”αžŸαŸ‹αž™αžΎαž„αž‘αŸ…αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸ

    gpg --keyserver keys.gnupg.net --send-key 2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    gpg: sending key 2D0D1706366FC4AEF79669E24D09C55BBA3FD728 to hkp server keys.gnupg.net

  • αž™αžΎαž„αž‘αž‘αž½αž›αž”αžΆαž“αžŸαŸ„αž―αž€αž‡αž“

    gpg --export-secret-keys --armor 2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    -----BEGIN PGP PRIVATE KEY BLOCK-----
    lQWGBFzAqp8BDADN41CPwJ/gQwiKEbyA902DKw/WSB1AvZQvV/ZFV77xGeG4K7k5
    ...
    =2Wd2
    -----END PGP PRIVATE KEY BLOCK-----

  • αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ -> αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹ -> CI / CD -> Variables αž αžΎαž™αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αžŸαŸ„αž―αž€αž‡αž“αž€αŸ’αž“αž»αž„αž’αžαŸαžš GPG_SECRET_KEY
    αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ Maven

  • αž”αž„αŸ’αž€αžΎαžαžŸαŸ„αž˜αŸ
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ -> αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹ -> CI / CD -> Variables αž αžΎαž™αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž€αŸ’αž“αž»αž„αž’αžαŸαžšαž˜αž½αž™αŸ” SETTINGS_SECURITY_XML αž”αž“αŸ’αž‘αžΆαžαŸ‹αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ–
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • αž€αžΆαžšαž’αŸŠαž·αž“αž‚αŸ’αžšαžΈαž”αž–αžΆαž€αŸ’αž™αžŸαž˜αŸ’αž„αžΆαžαŸ‹αž–αžΈαž‚αžŽαž“αžΈ Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ -> αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹ -> CI / CD -> Variables αž αžΎαž™αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž€αŸ’αž“αž»αž„αž’αžαŸαžšαž˜αž½αž™αŸ” SETTINGS_XML αž”αž“αŸ’αž‘αžΆαžαŸ‹αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ–
    <settings>  
    <profiles>
        <profile>
            <id>env</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <gpg.passphrase>GPG_SECRET_KEY_PASSPHRASE</gpg.passphrase>
            </properties>
        </profile>
    </profiles>
    <servers>
        <server>
            <id>sonatype</id>
            <username>sonatype_username</username>
            <password>{98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}</password>
        </server>
    </servers>
    </settings>

αž€αž“αŸ’αž›αŸ‚αž„αžŽαžΆ
GPG_SECRET_KEY_PASSHRASE - αž–αžΆαž€αŸ’αž™αžŸαž˜αŸ’αž„αžΆαžαŸ‹αžŸαŸ„ GPG
SONATYPE_USERNAME - αž…αžΌαž›αž‚αžŽαž“αžΈ sonatype

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αžšαžΌαž”αž—αžΆαž– docker

  • αž™αžΎαž„αž”αž„αŸ’αž€αžΎαž Dockerfile αžŠαŸαžŸαžΆαž˜αž‰αŸ’αž‰αž˜αž½αž™αžŠαžΎαž˜αŸ’αž”αžΈαžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž—αžΆαžšαž€αž·αž…αŸ’αž…αž‡αžΆαž˜αž½αž™αž€αŸ†αžŽαŸ‚αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžšαž“αŸƒ Java αŸ” αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αž“αŸαŸ‡αž‡αžΆαž§αž‘αžΆαž αžšαžŽαŸαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž—αŸ’αž“αŸ†αž’αžΆαž›αŸ‹αž•αŸ‚αž“αŸ”

    FROM java:8u111-jdk-alpine
    RUN apk add gnupg maven git --update-cache 
    --repository http://dl-4.alpinelinux.org/alpine/edge/community/ --allow-untrusted && 
    mkdir ~/.m2/

  • αž€αžΆαžšαžŸαžΆαž„αžŸαž„αŸ‹αž’αž»αž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ”

    docker build -t registry.gitlab.com/group/deploy .

  • αž™αžΎαž„αž•αŸ’αž‘αŸ€αž„αž•αŸ’αž‘αžΆαžαŸ‹ αž“αž·αž„αž•αŸ’αž‘αž»αž€αž€αž»αž„αžαžΊαž“αŸαžšαž‘αŸ…αž€αŸ’αž“αž»αž„αž”αž‰αŸ’αž‡αžΈαžˆαŸ’αž˜αŸ„αŸ‡αŸ”

    docker login -u USER -p PASSWORD registry.gitlab.com
    docker push registry.gitlab.com/group/deploy

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

GitLab αžŸαŸŠαžΈαž’αžΆαž™

αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αž‚αž˜αŸ’αžšαŸ„αž„

αž”αž“αŸ’αžαŸ‚αž˜αž―αž€αžŸαžΆαžš .gitlab-ci.yml αž‘αŸ…αž«αžŸαž“αŸƒαž‚αž˜αŸ’αžšαŸ„αž„αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™
αžŸαŸ’αž‚αŸ’αžšαžΈαž”αž”αž„αŸ’αž αžΆαž‰αž–αžΈαž€αž·αž…αŸ’αž…αž€αžΆαžšαžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αž•αŸ’αžαžΆαž…αŸ‹αž˜αž»αžαž–αžΈαžšαŸ” αž’αŸ’αž“αž€αžšαžαŸ‹αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹ αž¬αž’αŸ’αž“αž€αžšαžαŸ‹αž€αžΆαžšαž…αŸ‚αž€αžšαŸ†αž›αŸ‚αž€αžšαŸ€αž„αŸ—αžαŸ’αž›αž½αž“αŸ”

.gitlab-ci.yml

stages:
  - deploy

Specific Runner:
  extends: .java_deploy_template
  # Π—Π°Π΄Π°Ρ‡Π° Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ Π½Π° вашСм shell-Ρ€Π°Π½Π½Π΅Ρ€Π΅
  tags:
    - deploy

Shared Runner:
  extends: .java_deploy_template
  # Π—Π°Π΄Π°Ρ‡Π° Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ Π½Π° ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠΌ docker-Ρ€Π°Π½Π½Π΅Ρ€Π΅
  tags:
    - docker
  # ΠžΠ±Ρ€Π°Π· ΠΈΠ· Ρ€Π°Π·Π΄Π΅Π»Π° GitLab Runner -> Shared Runner -> Docker
  image: registry.gitlab.com/group/deploy-project:latest
  before_script:
    # Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ GPG ΠΊΠ»ΡŽΡ‡
    - printf "${GPG_SECRET_KEY}" | gpg --batch --import
    # БохраняСм maven ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ
    - printf "${SETTINGS_SECURITY_XML}" > ~/.m2/settings-security.xml
    - printf "${SETTINGS_XML}" > ~/.m2/settings.xml

.java_deploy_template:
  stage: deploy
  # Π—Π°Π΄Π°Ρ‡Π° сработаСт ΠΏΠΎ Ρ‚Ρ€ΠΈΠ³Π³Π΅Ρ€Ρƒ, Ссли ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π° пСрСмСнная DEPLOY со Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ java
  only:
    variables:
    - $DEPLOY == "java"
  variables:
    # ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΊΠ»ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°
    GIT_STRATEGY: none
  script:
    # ΠŸΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΠ΅ΠΌ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ хранСния пароля Π² Π½Π΅Π·Π°ΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Π½Π½ΠΎΠΌ Π²ΠΈΠ΄Π΅
    - git config --global credential.helper store
    # БохраняСм Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΊΡ€Π΅Π΄Ρ‹ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ gitlab-ci-token
    # Π’ΠΎΠΊΠ΅Π½ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ для всСх ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ² gitlab.com ΠΈ для ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ² Π³Ρ€ΡƒΠΏΠΏΡ‹
    - echo "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com" >> ~/.git-credentials
    # ΠŸΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ чистим Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ
    - rm -rf .* *
    # ΠšΠ»ΠΎΠ½ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ, Π±ΡƒΠ΄Π΅ΠΌ Π΄Π΅ΠΏΠ»ΠΎΠΈΡ‚ΡŒ Π² Sonatype Nexus
    - git clone ${DEPLOY_CI_REPOSITORY_URL} .
    # ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌΡΡ Π½Π° Π½ΡƒΠΆΠ½Ρ‹ΠΉ ΠΊΠΎΠΌΠΌΠΈΡ‚
    - git checkout ${DEPLOY_CI_COMMIT_SHA} -f
    # Если Ρ…ΠΎΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½ pom.xml содСрТит ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ autoReleaseAfterClose Π²Π°Π»ΠΈΠΌ сборку.
    # Π’ ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½ΠΎΠΌ случаС Π΅ΡΡ‚ΡŒ риск Π·Π°Π»ΠΈΡ‚ΡŒ сырыС Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Ρ‹ Π² maven central
    - >
      for pom in $(find . -name pom.xml); do
        if [[ $(grep -q autoReleaseAfterClose "$pom" && echo $?) == 0 ]]; then
          echo "File $pom contains prohibited setting: <autoReleaseAfterClose>";
          exit 1;
        fi;
      done
    # Если ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ DEPLOY_CI_COMMIT_TAG пустой, Ρ‚ΠΎ ΠΏΡ€ΠΈΠ½ΡƒΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ставим SNAPSHOT-Π²Π΅Ρ€ΡΠΈΡŽ
    - >
      if [[ "${DEPLOY_CI_COMMIT_TAG}" != "" ]]; then
        mvn versions:set -DnewVersion=${DEPLOY_CI_COMMIT_TAG}
      else
        VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
        if [[ "${VERSION}" == *-SNAPSHOT ]]; then
          mvn versions:set -DnewVersion=${VERSION}
        else
          mvn versions:set -DnewVersion=${VERSION}-SNAPSHOT
        fi
      fi
    # ЗапускаСм Π·Π°Π΄Π°Ρ‡Ρƒ Π½Π° сборку ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ΠΎΠ²
    - mvn clean deploy -DskipTests=true

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž‚αž˜αŸ’αžšαŸ„αž„ Java

αž“αŸ…αž€αŸ’αž“αž»αž„αž‚αž˜αŸ’αžšαŸ„αž„ java αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‚αŸαžŸαž“αŸ’αž˜αžαŸ‹αžαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž αŸ„αŸ‡αž‘αŸ…αž€αžΆαž“αŸ‹αžƒαŸ’αž›αžΆαŸ†αž„αžŸαžΆαž’αžΆαžšαžŽαŸˆ αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž”αž“αŸ’αžαŸ‚αž˜ 2 αž‡αŸ†αž αžΆαž“ αžŠαžΎαž˜αŸ’αž”αžΈαž‘αžΆαž‰αž™αž€αž€αŸ†αžŽαŸ‚αž…αŸαž‰αž•αŸ’αžŸαžΆαž™ αž“αž·αž„αžšαžΌαž”αžαžαŸ”

.gitlab-ci.yml

stages:
  - build
  - test
  - verify
  - deploy

<...>

Release:
  extends: .trigger_deploy
  # Π—Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π·Π°Π΄Π°Ρ‡Ρƒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏo Ρ‚Π΅Π³Ρƒ.
  only:
    - tags

Snapshot:
  extends: .trigger_deploy
  # ЗапускаСм Π·Π°Π΄Π°Ρ‡Ρƒ Π½Π° ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡŽ SNAPSHOT вСрсии Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ
  when: manual
  # НС Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π·Π°Π΄Π°Ρ‡Ρƒ, Ссли проставлСн Ρ‚Π΅Π³.
  except:
    - tags

.trigger_deploy:
  stage: deploy
  variables:
    # ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΊΠ»ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°
    GIT_STRATEGY: none
    # Бсылка Π½Π° Ρ‚Ρ€ΠΈΠ³Π³Π΅Ρ€ deploy-Π·Π°Π΄Π°Ρ‡ΠΈ
    URL: "https://gitlab.com/api/v4/projects/<deploy project ID>/trigger/pipeline"
    # ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ deploy-Π·Π°Π΄Π°Ρ‡ΠΈ
    POST_DATA: "
      token=${DEPLOY_TOKEN}&
      ref=master&
      variables[DEPLOY]=${DEPLOY}&
      variables[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
      variables[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
      variables[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
      variables[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
      "
  script:
    # НС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽ cURL, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ с Ρ„Π»Π°Π³Π°ΠΌΠΈ --fail --show-error
    # ΠΎΠ½ Π½Π΅ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ Ρ‚Π΅Π»ΠΎ ΠΎΡ‚Π²Π΅Ρ‚Π°, Ссли HTTP ΠΊΠΎΠ΄ 400 ΠΈ Π±ΠΎΠ»Π΅Π΅ 
    - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

αž€αŸ’αž“αž»αž„β€‹αžŠαŸ†αžŽαŸ„αŸ‡β€‹αžŸαŸ’αžšαžΆαž™β€‹αž“αŸαŸ‡ αžαŸ’αž‰αž»αŸ†β€‹αž”αžΆαž“β€‹αž”αž“αŸ’αžβ€‹αž”αž“αŸ’αžαž·αž…β€‹αž‘αŸ€αž αž αžΎαž™β€‹αž”αžΆαž“β€‹αžŸαž˜αŸ’αžšαŸαž…β€‹αž…αž·αžαŸ’αžβ€‹αž”αŸ’αžšαžΎβ€‹αž–αž»αž˜αŸ’αž– CI αž˜αž½αž™β€‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹β€‹αž‚αž˜αŸ’αžšαŸ„αž„ java αŸ”

αž–αŸαžαŸŒαž˜αžΆαž“αž›αž˜αŸ’αž’αž·αžαž”αž“αŸ’αžαŸ‚αž˜

αžαŸ’αž‰αž»αŸ†αž”αžΆαž“αž”αž„αŸ’αž€αžΎαžαž‚αž˜αŸ’αžšαŸ„αž„αžŠαžΆαž…αŸ‹αžŠαŸ„αž™αž‘αŸ‚αž€αž˜αž½αž™αŸ” gitlab-ci αžŠαŸ‚αž›αž‚αžΆαžαŸ‹αž”αžΆαž“αžŠαžΆαž€αŸ‹αž‚αŸ†αžšαžΌ CI αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ java common.yml.

common.yml

stages:
  - build
  - test
  - verify
  - deploy

variables:
  SONAR_ARGS: "
  -Dsonar.gitlab.commit_sha=${CI_COMMIT_SHA} 
  -Dsonar.gitlab.ref_name=${CI_COMMIT_REF_NAME} 
  "

.build_java_project:
  stage: build
  tags:
    - touchbit-shell
  variables:
    SKIP_TEST: "false"
  script:
    - mvn clean
    - mvn package -DskipTests=${SKIP_TEST}
  artifacts:
    when: always
    expire_in: 30 day
    paths:
      - "*/target/reports"

.build_sphinx_doc:
  stage: build
  tags:
    - touchbit-shell
  variables:
    DOCKERFILE: .indirect/docs/Dockerfile
  script:
    - docker build --no-cache -t ${CI_PROJECT_NAME}/doc -f ${DOCKERFILE} .

.junit_module_test_run:
  stage: test
  tags:
    - touchbit-shell
  variables:
    MODULE: ""
  script:
    - cd ${MODULE}
    - mvn test
  artifacts:
    when: always
    expire_in: 30 day
    paths:
      - "*/target/reports"

.junit_test_run:
  stage: test
  tags:
    - touchbit-shell
  script:
    - mvn test
  artifacts:
    when: always
    expire_in: 30 day
    paths:
    - "*/target/reports"

.sonar_review:
  stage: verify
  tags:
    - touchbit-shell
  dependencies: []
  script:
    - >
      if [ "$CI_BUILD_REF_NAME" == "master" ]; then
        mvn compile sonar:sonar -Dsonar.login=$SONAR_LOGIN $SONAR_ARGS
      else
        mvn compile sonar:sonar -Dsonar.login=$SONAR_LOGIN $SONAR_ARGS -Dsonar.analysis.mode=preview
      fi

.trigger_deploy:
  stage: deploy
  tags:
    - touchbit-shell
  variables:
    URL: "https://gitlab.com/api/v4/projects/10345765/trigger/pipeline"
    POST_DATA: "
      token=${DEPLOY_TOKEN}&
      ref=master&
      variables[DEPLOY]=${DEPLOY}&
      variables[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
      variables[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
      variables[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
      variables[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
      "
  script:
  - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

.trigger_release_deploy:
  extends: .trigger_deploy
  only:
    - tags

.trigger_snapshot_deploy:
  extends: .trigger_deploy
  when: manual
  except:
    - tags

αž‡αžΆαž›αž‘αŸ’αž’αž•αž› αž“αŸ…αž€αŸ’αž“αž»αž„αž‚αž˜αŸ’αžšαŸ„αž„ java αžαŸ’αž›αž½αž“αž―αž„ .gitlab-ci.yml αž˜αžΎαž›αž‘αŸ…αž˜αžΆαž“αž›αž€αŸ’αžαžŽαŸˆαžαžΌαž…αž…αž„αŸ’αž’αŸ€αž αž“αž·αž„αž˜αž·αž“αž˜αžΆαž“αž–αžΆαž€αŸ’αž™αžŸαŸ†αžŠαžΈ

.gitlab-ci.yml

include: https://gitlab.com/TouchBIT/gitlab-ci/raw/master/common.yml

Shields4J:
  extends: .build_java_project

Sphinx doc:
  extends: .build_sphinx_doc
  variables:
    DOCKERFILE: .docs/Dockerfile

Sonar review:
  extends: .sonar_review
  dependencies:
    - Shields4J

Release:
  extends: .trigger_release_deploy

Snapshot:
  extends: .trigger_snapshot_deploy

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’ pom.xml

αž”αŸ’αžšαž’αžΆαž“αž”αž‘αž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž–αž·αž–αžŽαŸŒαž“αžΆαž™αŸ‰αžΆαž„αž›αž˜αŸ’αž’αž·αžαŸ” Googolplex Π² αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ maven αžŠαžΎαž˜αŸ’αž”αžΈαž…αž»αŸ‡αž αžαŸ’αžαž›αŸαžαžΆαžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž· αž“αž·αž„αž”αž„αŸ’αž αŸ„αŸ‡αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽαž‘αŸ…αž€αž“αŸ’αž›αŸ‚αž„αž•αŸ’αž‘αž»αž€αžšαžΌαž”αžαž αž“αž·αž„αžŠαŸ†αžŽαžΆαž€αŸ‹αž€αžΆαž›αžŠαžΌαž…αŸ’αž“αŸαŸ‡ αžαŸ’αž‰αž»αŸ†β€‹αž“αžΉαž„β€‹αžšαŸ€αž”αžšαžΆαž”αŸ‹β€‹αž–αžΈβ€‹αž…αŸ†αžŽαž»αž…β€‹αžαŸ’αž›αŸ‡β€‹αž“αŸƒβ€‹αž€αžΆαžšβ€‹αž”αŸ’αžšαžΎβ€‹αž€αž˜αŸ’αž˜αžœαž·αž’αžΈβ€‹αž‡αŸ†αž“αž½αž™αŸ” αžαŸ’αž‰αž»αŸ†β€‹αž€αŸβ€‹αž“αžΉαž„β€‹αžšαŸ€αž”αžšαžΆαž”αŸ‹β€‹αž–αžΈβ€‹αžšαž”αŸ€αž”β€‹αžŠαŸ‚αž›β€‹αž’αŸ’αž“αž€β€‹αž’αžΆαž…β€‹αž”αŸ’αžšαžΎβ€‹αž”αžΆαž“β€‹αž™αŸ‰αžΆαž„β€‹αž„αžΆαž™β€‹αžŸαŸ’αžšαž½αž›β€‹αž“αž·αž„β€‹αž’αž˜αŸ’αž˜αž‡αžΆαžαž· nexus-staging-maven-pluginαž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž˜αž·αž“αž…αž„αŸ‹ αž¬αž˜αž·αž“αž’αžΆαž…αž”αŸ’αžšαžΎ org.sonatype.oss:oss-parent αž‡αžΆαž˜αŸαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ”

maven-install-plugin

αžŠαŸ†αž‘αžΎαž„αž˜αŸ‰αžΌαžŒαž»αž›αž“αŸ…αž€αŸ’αž“αž»αž„αžƒαŸ’αž›αžΆαŸ†αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αŸ”
αž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαžαŸ’αž›αžΆαŸ†αž„αžŽαžΆαžŸαŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž•αŸ’αž‘αŸ€αž„αž•αŸ’αž‘αžΆαžαŸ‹αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž“αŸƒαžŠαŸ†αžŽαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž“αŸ…αž€αŸ’αž“αž»αž„αž‚αž˜αŸ’αžšαŸ„αž„αž•αŸ’αžŸαŸαž„αž‘αŸ€αž αž€αŸαžŠαžΌαž…αž‡αžΆαž€αžΆαžšαž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αŸ”

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-install-plugin</artifactId>
  <executions>
    <execution>
      <id>install-project</id>
      <!-- Если Ρƒ вас ΠΌΠ½ΠΎΠ³ΠΎΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½Ρ‹ΠΉ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ с Π΄Π΅ΠΏΠ»ΠΎΠ΅ΠΌ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ ΠΏΠΎΠΌΠΈΠΊΠ° -->
      <phase>install</phase>
      <!-- Π―Π²Π½ΠΎ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Ρ„Π°ΠΉΠ»Ρ‹ для локальной установки -->
      <configuration>
        <file>target/${project.artifactId}-${project.version}.jar</file>
```target/${project.artifactId}-${project.version}-sources.jar</sources>
        <pomFile>dependency-reduced-pom.xml</pomFile>
        <!-- ΠŸΡ€ΠΈΠ½ΡƒΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° -->
        <updateReleaseInfo>true</updateReleaseInfo>
        <!-- ΠšΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½Ρ‹Π΅ суммы для ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ цСлостности -->
        <createChecksum>true</createChecksum>
      </configuration>
    </execution>
  </executions>
</plugin>

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

maven-javadoc-plugin

αž€αžΆαžšαž”αž„αŸ’αž€αžΎαž javadoc αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„αŸ”

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-javadoc-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>jar</goal>
      </goals>
      <!-- ГСнСрация javadoc Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ послС Ρ„Π°Π·Ρ‹ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ рСсурсов -->
      <phase>prepare-package</phase>
      <configuration>
        <!-- ΠžΡ‡Π΅Π½ΡŒ ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ Π² ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°Ρ… -->
        <failOnError>true</failOnError>
        <failOnWarnings>true</failOnWarnings>
        <!-- Π£Π±ΠΈΡ€Π°Π΅Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ поиска Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π² target Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ -->
        <detectOfflineLinks>false</detectOfflineLinks>
      </configuration>
    </execution>
  </executions>
</plugin>

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž˜αžΆαž“αž˜αŸ‰αžΌαžŒαž»αž›αžŠαŸ‚αž›αž˜αž·αž“αž˜αžΆαž“ java (αž§αž‘αžΆαž αžšαžŽαŸαžαŸ‚αž’αž“αž’αžΆαž“)
αž¬αž’αŸ’αž“αž€αž˜αž·αž“αž…αž„αŸ‹αž”αž„αŸ’αž€αžΎαž javadoc αž‡αžΆαž‚αŸ„αž›αž€αžΆαžšαžŽαŸ αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž‡αž½αž™ maven-jar-plugin

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <executions>
    <execution>
      <id>empty-javadoc-jar</id>
      <phase>generate-resources</phase>
      <goals>
        <goal>jar</goal>
      </goals>
      <configuration>
        <classifier>javadoc</classifier>
        <classesDirectory>${basedir}/javadoc</classesDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

maven-gpg-plugin

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-gpg-plugin</artifactId>
  <executions>
    <execution>
      <id>sign-artifacts</id>
      <!-- Π‘Π±ΠΎΡ€ΠΊΠ° Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ°Π΄Π°Ρ‚ΡŒ, Ссли отсутствуСт GPG ΠΊΠ»ΡŽΡ‡ -->
      <!-- ΠŸΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°Π΅ΠΌ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° Ρ„Π°Π·Π΅ deploy -->
      <phase>deploy</phase>
      <goals>
        <goal>sign</goal>
      </goals>
    </execution>
  </executions>
</plugin>

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

nexus-staging-maven-plugin

αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹β€‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’:

<project>
  <!-- ... -->
  <build>
    <plugins>
      <!-- ... -->
      <plugin>
        <groupId>org.sonatype.plugins</groupId>
        <artifactId>nexus-staging-maven-plugin</artifactId>
      </plugin>
    </plugins>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.sonatype.plugins</groupId>
          <artifactId>nexus-staging-maven-plugin</artifactId>
          <extensions>true</extensions>
          <configuration>
            <serverId>sonatype</serverId>
            <nexusUrl>https://oss.sonatype.org/</nexusUrl>
            <!-- ОбновляСм ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ ΠΊΠ°ΠΊ release -->
            <!-- НС влияСт Π½Π° snapshot вСрсии -->
            <updateReleaseInfo>true</updateReleaseInfo>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-deploy-plugin</artifactId>
          <configuration>
            <!-- ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½ -->
            <skip>true</skip>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
  <distributionManagement>
    <snapshotRepository>
      <id>sonatype</id>
      <name>Nexus Snapshot Repository</name>
      <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
    </snapshotRepository>
    <repository>
      <id>sonatype</id>
      <name>Nexus Release Repository</name>
      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
    </repository>
  </distributionManagement>
</project>

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž˜αžΆαž“αž‚αž˜αŸ’αžšαŸ„αž„αž–αž αž»αž˜αŸ‰αžΌαžŒαž»αž› αž αžΎαž™αž’αŸ’αž“αž€αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αž•αŸ’αž‘αž»αž€αž˜αŸ‰αžΌαžŒαž»αž›αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αž˜αž½αž™αž‘αŸ…αžƒαŸ’αž›αžΆαŸ†αž„αž‘αŸαž“αŸ„αŸ‡ αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž”αž“αŸ’αžαŸ‚αž˜ nexus-staging-maven-plugin αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž‘αž„αŸ‹αž‡αžΆαžαž· skipNexusStagingDeployMojo

<build>
  <plugins>
    <plugin>
      <groupId>org.sonatype.plugins</groupId>
      <artifactId>nexus-staging-maven-plugin</artifactId>
      <configuration>
        <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo>
      </configuration>
    </plugin>
  </plugins>
</build>

αž”αž“αŸ’αž‘αžΆαž”αŸ‹β€‹αž–αžΈβ€‹αž€αžΆαžšβ€‹αž”αž„αŸ’αž αŸ„αŸ‡β€‹αžšαžΌαž”β€‹αžαž/αž€αŸ†αžŽαŸ‚β€‹αž…αŸαž‰β€‹αž•αŸ’αžŸαžΆαž™β€‹αž˜αžΆαž“β€‹αž“αŸ…β€‹αž€αŸ’αž“αž»αž„ αž€αž“αŸ’αž›αŸ‚αž„αžŸαŸ’αžαž»αž€αž‘αž»αž€αžŠαŸ†αžŽαžΆαž€αŸ‹αž€αžΆαž›

<repositories>
  <repository>
    <id>SonatypeNexus</id>
    <url>https://oss.sonatype.org/content/groups/staging/</url>
    <!-- НС Π½Π°Π΄ΠΎ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ„Π»Π°Π³ΠΈ snapshot/release для рСпозитория -->
  </repository>
</repositories>

pluses αž…αŸ’αžšαžΎαž“αž‘αŸ€αž

  • αž”αž‰αŸ’αž‡αžΈαž‚αŸ„αž›αžŠαŸ…αžŠαŸαžŸαž˜αŸ’αž”αžΌαžšαž”αŸ‚αž”αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αžƒαŸ’αž›αžΆαŸ†αž„αž‘αŸ†αž“αžΆαž€αŸ‹αž‘αŸ†αž“αž„ (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • αž€αžΆαžšαž…αŸαž‰αž•αŸ’αžŸαžΆαž™αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αž›αž‘αŸ’αž’αž—αžΆαž–αž‘αžΆαž‰αž™αž€αž“αŸ…αž€αŸ’αž“αž»αž„ maven central

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž›αž‘αŸ’αž’αž•αž›

αž€αžΆαžšαž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž€αŸ†αžŽαŸ‚ SNAPSHOT

αž“αŸ…αž–αŸαž›αžŸαžΆαž„αžŸαž„αŸ‹αž‚αž˜αŸ’αžšαŸ„αž„ αžœαžΆαž’αžΆαž…αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž—αžΆαžšαž€αž·αž…αŸ’αž…αžŠαŸ„αž™αžŠαŸƒαžŠαžΎαž˜αŸ’αž”αžΈαž‘αžΆαž‰αž™αž€αž€αŸ†αžŽαŸ‚ SNAPSHOT αž‘αŸ…αž—αŸ’αž‡αžΆαž”αŸ‹

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž€αž·αž…αŸ’αž…αž€αžΆαžšαž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜ αž€αž·αž…αŸ’αž…αž€αžΆαžšαžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž‚αŸ’αž“αžΆαž“αŸ…αž€αŸ’αž“αž»αž„αž‚αž˜αŸ’αžšαŸ„αž„αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸαŸ‡ (αž§αž‘αžΆαž αžšαžŽαŸ).

αž€αŸ†αžŽαžαŸ‹αž αŸαžαž»αžŠαŸ‚αž›αž”αžΆαž“αž…αŸ’αžšαžΉαž”

Running with gitlab-runner 11.10.0 (3001a600)
  on Deploy runner JSKWyxUw
Using Shell executor...
Running on ih1174328.vds.myihor.ru...
Skipping Git repository setup
Skipping Git checkout
Skipping Git submodules setup
$ rm -rf .* *
$ git config --global credential.helper store
$ echo "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com" >> ~/.git-credentials
$ git clone ${DEPLOY_CI_REPOSITORY_URL} .
Cloning into 'shields4j'...
$ git checkout ${DEPLOY_CI_COMMIT_SHA}
Note: checking out '850f86aa317194395c5387790da1350e437125a7'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
  git checkout -b new_branch_name
HEAD is now at 850f86a... skip deploy test-core
$ for pom in $(find . -name pom.xml); do # collapsed multi-line command
$ if [[ "${DEPLOY_CI_COMMIT_TAG}" != "" ]]; then # collapsed multi-line command
[INFO] Scanning for projects...
[INFO] Inspecting build with total of 4 modules...
[INFO] Installing Nexus Staging features:
[INFO]   ... total of 4 executions of maven-deploy-plugin replaced with nexus-staging-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] Shields4J                                                          [pom]
[INFO] test-core                                                          [jar]
[INFO] Shields4J client                                                   [jar]
[INFO] TestNG listener                                                    [jar]
[INFO] 
[INFO] --------------< org.touchbit.shields4j:shields4j-parent >---------------
[INFO] Building Shields4J 1.0.0                                           [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- versions-maven-plugin:2.5:set (default-cli) @ shields4j-parent ---
[INFO] Searching for local aggregator root...
[INFO] Local aggregation root: /home/gitlab-deployer/JSKWyxUw/0/TouchBIT/deploy/shields4j
[INFO] Processing change of org.touchbit.shields4j:shields4j-parent:1.0.0 -> 1.0.0-SNAPSHOT
[INFO] Processing org.touchbit.shields4j:shields4j-parent
[INFO]     Updating project org.touchbit.shields4j:shields4j-parent
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO] 
[INFO] Processing org.touchbit.shields4j:client
[INFO]     Updating parent org.touchbit.shields4j:shields4j-parent
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO]     Updating dependency org.touchbit.shields4j:test-core
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO] 
[INFO] Processing org.touchbit.shields4j:test-core
[INFO]     Updating parent org.touchbit.shields4j:shields4j-parent
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO] 
[INFO] Processing org.touchbit.shields4j:testng
[INFO]     Updating parent org.touchbit.shields4j:shields4j-parent
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO]     Updating dependency org.touchbit.shields4j:client
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO]     Updating dependency org.touchbit.shields4j:test-core
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUCCESS [  0.992 s]
[INFO] test-core .......................................... SKIPPED
[INFO] Shields4J client ................................... SKIPPED
[INFO] TestNG listener 1.0.0 .............................. SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.483 s
[INFO] Finished at: 2019-04-21T02:40:42+03:00
[INFO] ------------------------------------------------------------------------
$ mvn clean deploy -DskipTests=${SKIP_TESTS}
[INFO] Scanning for projects...
[INFO] Inspecting build with total of 4 modules...
[INFO] Installing Nexus Staging features:
[INFO]   ... total of 4 executions of maven-deploy-plugin replaced with nexus-staging-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] Shields4J                                                          [pom]
[INFO] test-core                                                          [jar]
[INFO] Shields4J client                                                   [jar]
[INFO] TestNG listener                                                    [jar]
[INFO] 
[INFO] --------------< org.touchbit.shields4j:shields4j-parent >---------------
[INFO] Building Shields4J 1.0.0-SNAPSHOT                                  [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
...
DELETED
...
[INFO]  * Bulk deploy of locally gathered snapshot artifacts finished.
[INFO] Remote deploy finished with success.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Shields4J 1.0.0-SNAPSHOT ........................... SUCCESS [  2.375 s]
[INFO] test-core .......................................... SUCCESS [  3.929 s]
[INFO] Shields4J client ................................... SUCCESS [  3.815 s]
[INFO] TestNG listener 1.0.0-SNAPSHOT ..................... SUCCESS [ 36.134 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 47.629 s
[INFO] Finished at: 2019-04-21T02:41:32+03:00
[INFO] ------------------------------------------------------------------------

αž‡αžΆαž›αž‘αŸ’αž’αž•αž›αž€αŸ†αžŽαŸ‚ nexus αžαŸ’αžšαžΌαžœαž”αžΆαž“αž•αŸ’αž‘αž»αž€ 1.0.0- αžšαžΌαž”αžαž.

αž€αŸ†αžŽαŸ‚αžšαžΌαž”αžαžαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž™αž€αž…αŸαž‰αž–αžΈαžƒαŸ’αž›αžΆαŸ†αž„αž“αŸ…αž›αžΎαž‚αŸαž αž‘αŸ†αž–αŸαžš oss.sonatype.org αž“αŸ…αž€αŸ’αžšαŸ„αž˜αž‚αžŽαž“αžΈαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ”

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž€αžΆαžšαž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž€αŸ†αžŽαŸ‚αž…αŸαž‰αž•αŸ’αžŸαžΆαž™

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αžŸαŸ’αž›αžΆαž€αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹ αž€αž·αž…αŸ’αž…αž€αžΆαžšαžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž‚αŸ’αž“αžΆαž“αŸ…αž€αŸ’αž“αž»αž„αž‚αž˜αŸ’αžšαŸ„αž„αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž€αž‘αžΎαž„αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž· αžŠαžΎαž˜αŸ’αž”αžΈαž•αŸ’αž‘αž»αž€αž€αŸ†αžŽαŸ‚αž…αŸαž‰αž•αŸ’αžŸαžΆαž™αž‘αŸ… nexus (αž§αž‘αžΆαž αžšαžŽαŸ).

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

αž•αŸ’αž“αŸ‚αž€αžŠαŸαž›αŸ’αž’αž”αŸ†αž•αž»αžαž‚αžΊαžαžΆαž€αžΆαžšαž…αŸαž‰αž•αŸ’αžŸαžΆαž™αž”αž·αž‘αž”αžΎαž€αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αž“αŸ…αž€αŸ’αž“αž»αž„ Nexus αŸ”

[INFO] Performing remote staging...
[INFO] 
[INFO]  * Remote staging into staging profile ID "9043b43f77dcc9"
[INFO]  * Created staging repository with ID "orgtouchbit-1037".
[INFO]  * Staging repository at https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1037
[INFO]  * Uploading locally staged artifacts to profile org.touchbit
[INFO]  * Upload of locally staged artifacts finished.
[INFO]  * Closing staging repository with ID "orgtouchbit-1037".
Waiting for operation to complete...
.........
[INFO] Remote staged 1 repositories, finished with success.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUCCESS [  9.603 s]
[INFO] test-core .......................................... SUCCESS [  3.419 s]
[INFO] Shields4J client ................................... SUCCESS [  9.793 s]
[INFO] TestNG listener 1.0.0 .............................. SUCCESS [01:23 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:47 min
[INFO] Finished at: 2019-04-21T04:05:46+03:00
[INFO] ------------------------------------------------------------------------

αž αžΎαž™αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“αž’αŸ’αžœαžΈαž˜αž½αž™αžαž»αžŸ αž“αŸ„αŸ‡αž€αž·αž…αŸ’αž…αž€αžΆαžšαž“αžΉαž„αž”αžšαžΆαž‡αŸαž™

[INFO] Performing remote staging...
[INFO] 
[INFO]  * Remote staging into staging profile ID "9043b43f77dcc9"
[INFO]  * Created staging repository with ID "orgtouchbit-1038".
[INFO]  * Staging repository at https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1038
[INFO]  * Uploading locally staged artifacts to profile org.touchbit
[INFO]  * Upload of locally staged artifacts finished.
[INFO]  * Closing staging repository with ID "orgtouchbit-1038".
Waiting for operation to complete...
.......
[ERROR] Rule failure while trying to close staging repository with ID "orgtouchbit-1039".
[ERROR] 
[ERROR] Nexus Staging Rules Failure Report
[ERROR] ==================================
[ERROR] 
[ERROR] Repository "orgtouchbit-1039" failures
[ERROR]   Rule "signature-staging" failures
[ERROR]     * No public key: Key with id: (1f42b618d1cbe1b5) was not able to be located on &lt;a href=http://keys.gnupg.net:11371/&gt;http://keys.gnupg.net:11371/&lt;/a&gt;. Upload your public key and try the operation again.
...
[ERROR] Cleaning up local stage directory after a Rule failure during close of staging repositories: [orgtouchbit-1039]
[ERROR]  * Deleting context 9043b43f77dcc9.properties
[ERROR] Cleaning up remote stage repositories after a Rule failure during close of staging repositories: [orgtouchbit-1039]
[ERROR]  * Dropping failed staging repository with ID "orgtouchbit-1039" (Rule failure during close of staging repositories: [orgtouchbit-1039]).
[ERROR] Remote staging finished with a failure: Staging rules failure!
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUCCESS [  4.073 s]
[INFO] test-core .......................................... SUCCESS [  2.788 s]
[INFO] Shields4J client ................................... SUCCESS [  3.962 s]
[INFO] TestNG listener 1.0.0 .............................. FAILURE [01:07 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

αž‡αžΆαž›αž‘αŸ’αž’αž•αž› αž™αžΎαž„αž“αŸ…αžŸαž›αŸ‹αžαŸ‚αž‡αž˜αŸ’αžšαžΎαžŸαž˜αž½αž™αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡αŸ” αž¬αž›αž»αž”αž€αŸ†αžŽαŸ‚αž“αŸαŸ‡ αž¬αž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž•αŸ’αžŸαžΆαž™αŸ”

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž€αžΆαžšαž…αŸαž‰αž•αŸ’αžŸαžΆαž™ αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽαž“αžΉαž„αž…αžΌαž› αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αŸ„αŸ‡αž‚αž˜αŸ’αžšαŸ„αž„ java αž‘αŸ…αž€αžΆαž“αŸ‹ maven central

αž…αžΆαž€αž”αŸ’αžšαž’αžΆαž“

αžœαžΆαž‚αžΊαž‡αžΆαžœαž·αžœαžšαžŽαŸˆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαŸ’αž‰αž»αŸ†αžŠαŸ‚αž› maven αž’αŸ’αžœαžΎαž›αž·αž”αž·αž€αŸ’αžšαž˜αžƒαŸ’αž›αžΆαŸ†αž„αžŸαžΆαž’αžΆαžšαžŽαŸˆαž•αŸ’αžŸαŸαž„αž‘αŸ€αžαŸ”
αžαŸ’αž‰αž»αŸ†αžαŸ’αžšαžΌαžœαž”αž“αŸ’αžαŸ‚αž˜ robots.txt αž–αŸ’αžšαŸ„αŸ‡αžœαžΆαž’αŸ’αžœαžΎαž›αž·αž”αž·αž€αŸ’αžšαž˜αžƒαŸ’αž›αžΆαŸ†αž„αž…αžΆαžŸαŸ‹αžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†αŸ”

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αžŸαŸαž…αž€αŸ’αžαžΈαžŸαž“αŸ’αž“αž·αžŠαŸ’αž‹αžΆαž“

αž’αŸ’αžœαžΈαžŠαŸ‚αž›αž™αžΎαž„αž˜αžΆαž“

  • αž‚αž˜αŸ’αžšαŸ„αž„αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αžŠαžΆαž…αŸ‹αžŠαŸ„αž™αž‘αŸ‚αž€ αžŠαŸ‚αž›αž’αŸ’αž“αž€αž’αžΆαž…αž’αž“αž»αžœαžαŸ’αžαž€αž·αž…αŸ’αž…αž€αžΆαžš CI αž‡αžΆαž…αŸ’αžšαžΎαž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αž„αŸ’αž αŸ„αŸ‡αžœαžαŸ’αžαž»αž”αž»αžšαžΆαžŽαž‘αŸ…αž€αžΆαž“αŸ‹αžƒαŸ’αž›αžΆαŸ†αž„αžŸαžΆαž’αžΆαžšαžŽαŸˆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž—αžΆαžŸαžΆαž’αž—αž·αžœαžŒαŸ’αžαž“αŸαž•αŸ’αžŸαŸαž„αŸ—αŸ”
  • αž‚αž˜αŸ’αžšαŸ„αž„αžŠαžΆαž€αŸ‹αž–αž„αŸ’αžšαžΆαž™αž‚αžΊαžŠαžΆαž…αŸ‹αžŠαŸ„αž™αž‘αŸ‚αž€αž–αžΈαž€αžΆαžšαž‡αŸ’αžšαŸ€αžαž‡αŸ’αžšαŸ‚αž€αž–αžΈαžαžΆαž„αž€αŸ’αžšαŸ… αž αžΎαž™αž’αžΆαž…αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž”αžΆαž“αžŠαŸ„αž™αž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αžŠαŸ‚αž›αž˜αžΆαž“αžαž½αž“αžΆαž‘αžΈαž˜αŸ’αž…αžΆαžŸαŸ‹ αž“αž·αž„αž’αŸ’αž“αž€αžαŸ‚αž‘αžΆαŸ†αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡αŸ”
  • αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαžšαžαŸ‹αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αžŠαžΆαž…αŸ‹αžŠαŸ„αž™αž‘αŸ‚αž€αžŠαŸ‚αž›αž˜αžΆαž“αžƒαŸ’αž›αžΆαŸ†αž„αžŸαž˜αŸ’αž„αžΆαžαŸ‹ "αž€αŸ’αžαŸ…" αžŠαžΎαž˜αŸ’αž”αžΈαžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžαŸ‚αž—αžΆαžšαž€αž·αž…αŸ’αž…αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡αŸ”
  • αž€αžΆαžšαž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž•αŸ’αžŸαžΆαž™αžšαžΌαž”αžαž/αž€αŸ†αžŽαŸ‚αž…αŸαž‰αž•αŸ’αžŸαžΆαž™αž“αŸ…αž€αŸ’αž“αž»αž„αžƒαŸ’αž›αžΆαŸ†αž„αžŸαžΆαž’αžΆαžšαžŽαŸˆαŸ”
  • αž–αž·αž“αž·αžαŸ’αž™αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αž“αŸƒαž€αŸ†αžŽαŸ‚αž…αŸαž‰αž•αŸ’αžŸαžΆαž™αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαžαŸ’αžšαŸ€αž˜αžαŸ’αž›αž½αž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž•αŸ’αžŸαžΆαž™αž“αŸ…αž€αŸ’αž“αž»αž„ maven central αŸ”
  • αž€αžΆαžšαž€αžΆαžšαž–αžΆαžšαž”αŸ’αžšαž†αžΆαŸ†αž„αž“αžΉαž„αž€αžΆαžšαž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αž“αŸƒαž€αŸ†αžŽαŸ‚ "αž†αŸ…" αž“αŸ…αž€αŸ’αž“αž»αž„ maven central αŸ”
  • αž”αž„αŸ’αž€αžΎαž αž“αž·αž„αž”αŸ„αŸ‡αž•αŸ’αžŸαžΆαž™αž€αŸ†αžŽαŸ‚αžšαžΌαž”αžαž "αž“αŸ…αž›αžΎαž€αžΆαžšαž…αž»αž…" αŸ”
  • αžƒαŸ’αž›αžΆαŸ†αž„αžαŸ‚αž˜αž½αž™αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž‘αž‘αž½αž›αž”αžΆαž“αžšαžΌαž”αžαž/αž€αŸ†αžŽαŸ‚αž…αŸαž‰αž•αŸ’αžŸαžΆαž™αŸ”
  • αž”αŸ†αž–αž„αŸ‹αž”αž„αŸ’αž αžΌαžšαž”αŸ’αžšαŸαž„αž‘αžΌαž‘αŸ…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαžΆαž„αžŸαž„αŸ‹/αžŸαžΆαž€αž›αŸ’αž”αž„/αž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž‚αž˜αŸ’αžšαŸ„αž„ java αŸ”

αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ GitLab CI αž‚αžΊαž˜αž·αž“αžŸαŸ’αž˜αž»αž‚αžŸαŸ’αž˜αžΆαž‰αžŠαžΌαž…αž”αŸ’αžšαž’αžΆαž“αž”αž‘αžŠαžΌαž…αžŠαŸ‚αž›αžœαžΆαž αžΆαž€αŸ‹αžŠαžΌαž…αž‡αžΆαž“αŸ… glance αžŠαŸ†αž”αžΌαž„αŸ” αžœαžΆαž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαžΆαž“αŸ‹αž αžΎαž™αž€αŸ’αž“αž»αž„αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ CI αž“αŸ…αž›αžΎαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“ turnkey αž–αžΈαžšαž”αžΈαžŠαž„ αž αžΎαž™αž₯αž‘αžΌαžœαž“αŸαŸ‡αž’αŸ’αž“αž€αž“αŸ…αž†αŸ’αž„αžΆαž™αž–αžΈαž’αŸ’αž“αž€αžŸαŸ’αž˜αŸαž‚αŸ’αžšαž…αž·αžαŸ’αžαž“αŸ…αž€αŸ’αž“αž»αž„αž”αž‰αŸ’αž αžΆαž“αŸαŸ‡αŸ” αž›αžΎαžŸαž–αžΈαž“αŸαŸ‡αž‘αŸ…αž‘αŸ€αž αž―αž€αžŸαžΆαžš GitLab αž‚αžΊαž˜αž·αž“αž˜αžΆαž“αž…αŸ’αžšαžΎαž“αž‘αŸαŸ” αž€αž»αŸ†αžαŸ’αž›αžΆαž…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αŸ„αŸ‡αž‡αŸ†αž αžΆαž“αžŠαŸ†αž”αžΌαž„αŸ” αž•αŸ’αž›αžΌαžœβ€‹αž›αŸαž…β€‹αž€αŸ’αžšαŸ„αž˜β€‹αž‡αŸ†αž αžΆαž“β€‹αž’αŸ’αž“αž€β€‹αžŠαžΎαžš (αžαŸ’αž‰αž»αŸ†β€‹αž˜αž·αž“β€‹αž…αžΆαŸ†β€‹αžαžΆβ€‹αž’αŸ’αž“αž€β€‹αžŽαžΆβ€‹αž“αž·αž™αžΆαž™β€‹αž‘αŸ :)

αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αžšαžΈαž€αžšαžΆαž™αž…αŸ†αž–αŸ„αŸ‡αž˜αžαž·αž€αŸ‚αž›αž˜αŸ’αž’αŸ”

αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘αž”αž“αŸ’αž‘αžΆαž”αŸ‹ αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž”αž„αŸ’αž αžΆαž‰αž’αŸ’αž“αž€αž–αžΈαžšαž”αŸ€αž”αžŠαŸ†αž‘αžΎαž„ GitLab CI αžŠαžΎαž˜αŸ’αž”αžΈαžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž€αž·αž…αŸ’αž…αž€αžΆαžšαžŸαžΆαž€αž›αŸ’αž”αž„αžŸαž˜αžΆαž αžšαžŽαž€αž˜αŸ’αž˜αž”αŸ’αžšαž€αž”αžŠαŸ„αž™αž€αžΆαžšαž”αŸ’αžšαž€αž½αžαž”αŸ’αžšαž‡αŸ‚αž„ (αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αžŸαžΆαž€αž›αŸ’αž”αž„αž‡αžΆαž˜αž½αž™ docker-compose) αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž˜αžΆαž“αž’αŸ’αž“αž€αžšαžαŸ‹αžŸαŸ‚αž›αžαŸ‚αž˜αž½αž™αŸ”

αž‘αŸ…αž˜αžΆαžαž·αž€αžΆ

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹