рдмрд┐рд▓реНрдбрдмреЙрдЯ: рдПрдХ рдЕрдиреНрдп рд╕рддрдд рдПрдХреАрдХрд░рдг рдкреНрд░рдгрд╛рд▓реА рдХреЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдХрд╣рд╛рдиреА


( рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рд╕рд╛рдЗрдЯ рд╕реЗ рддрд╕реНрд╡реАрд░)

рдмрд┐рд▓реНрдбрдмреЛрдЯ, рдЬреИрд╕рд╛ рдХрд┐ рдирд╛рдо рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ, рдПрдХ рдирд┐рд░рдВрддрд░ рдПрдХреАрдХрд░рдг рдкреНрд░рдгрд╛рд▓реА (рд╕реАрдЖрдИ) рд╣реИред рд╣реЛрдмреЗ рдкрд░ рдЙрдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрдИ рд▓реЗрдЦ рдереЗ, рд▓реЗрдХрд┐рди, рдореЗрд░реЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ, рдЗрд╕ рдЙрдкрдХрд░рдг рдХреЗ рдлрд╛рдпрджреЗ рдЙрдирд╕реЗ рдмрд╣реБрдд рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЙрдирдХреЗ рдкрд╛рд╕ рд▓рдЧрднрдЧ рдХреЛрдИ рдЙрджрд╛рд╣рд░рдг рдирд╣реАрдВ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреА рдкреВрд░реА рд╢рдХреНрддрд┐ рдХреЛ рджреЗрдЦрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдЕрдкрдиреЗ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рдЗрди рдХрдорд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛, рдмрд┐рд▓реНрдбрдмреЛрдЯ рдХреА рдЖрдВрддрд░рд┐рдХ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реВрдВрдЧрд╛, рдФрд░ рдХрдИ рдЧреИрд░-рдорд╛рдирдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рджреВрдВрдЧрд╛ред

рдЖрдо рд╢рдмреНрдж


рд╡рд░реНрддрдорд╛рди рдореЗрдВ, рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдирд┐рд░рдВрддрд░ рдПрдХреАрдХрд░рдг рдкреНрд░рдгрд╛рд▓рд┐рдпрд╛рдВ рд╣реИрдВ, рдФрд░ рдЬрдм рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рдХреА рдмрд╛рдд рдЖрддреА рд╣реИ, рддреЛ "рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ <program_name>" рд╣реЛрдиреЗ рдкрд░ рдФрд░ "рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ" рдХреА рднрд╛рд╡рдирд╛ рдореЗрдВ рдХрд╛рдлреА рддрд╛рд░реНрдХрд┐рдХ рдкреНрд░рд╢реНрди рдЙрдарддреЗ рд╣реИрдВ? рдореИрдВ рдмрд┐рд▓реНрдбрдмреЙрдЯ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХреЗ рд╕рд╡рд╛рд▓ рдХрд╛ рдЬрд╡рд╛рдм рджреЗрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ред рдХреБрдЫ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдореМрдЬреВрджрд╛ рд▓реЗрдЦреЛрдВ рдХреЗ рд╕рд╛рде рджреЛрд╣рд░рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдХреБрдЫ рдХреЛ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдкреНрд░рд▓реЗрдЦрди рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдХрдерд╛ рдХреА рд╕реНрдерд┐рд░рддрд╛ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред

рдирд┐рд░рдВрддрд░ рдПрдХреАрдХрд░рдг рдХреА рдЕрдиреНрдп рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рд╕реЗ рдореБрдЦреНрдп рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ рдмрд┐рд▓реНрдбрдмреЛрдЯ ci рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рдпрдерди рдлреНрд░реЗрдорд╡рд░реНрдХ рд╣реИ, рдФрд░ рдмреЙрдХреНрд╕ рд╕реЗ рдХреЛрдИ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ рдПрдХ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЛ рдмрд┐рд▓реНрдбрдмреЛрдЯ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рдмрд┐рд▓реНрдбрдмреЙрдЯ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдЕрд▓рдЧ рдЕрдЬрдЧрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдо рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ рдЬреЛ рдЖрдкрдХреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреА рдирд┐рд░рдВрддрд░рддрд╛ рдХреА рдирд┐рд░рдВрддрд░рддрд╛ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдЬрдмрд░рджрд╕реНрдд рд▓рдЪреАрд▓рд╛рдкрди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдЖрдкрдХреЛ рдЯреНрд░рд┐рдХреА рдкрд░реАрдХреНрд╖рдг рдкрд░рд┐рджреГрд╢реНрдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдорд┐рд▓рддреА рд╣реИ рдЬреЛ рд╡рд╛рд╕реНрддреБ рд╕реАрдорд╛рдУрдВ рдХреЗ рдХрд╛рд░рдг рдЖрдЙрдЯ-рдСрдл-рдмреЙрдХреНрд╕ рд╕рдорд╛рдзрд╛рди рдХреЗ рд▓рд┐рдП рдЕрд╕рдВрднрд╡ рд╣реИрдВред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдмрд┐рд▓реНрдбрдмреЛрдЯ рдПрдХ рд╕реЗрд╡рд╛ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ рдЗрд╕реЗ рдЕрдкрдиреЗ рдмреБрдирд┐рдпрд╛рджреА рдврд╛рдВрдЪреЗ рдкрд░ рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ рддреИрдирд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрд╣рд╛рдВ рдореИрдВрдиреЗ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдХрд┐ рдлреНрд░реЗрдорд╡рд░реНрдХ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рд╡рдлрд╛рджрд╛рд░ рд╣реИред рдпрд╣ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ C рдпрд╛ C ++ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЬрдЧрд░ рдЕрдкрдиреЗ рдЬрд╛рд╡рд╛ рдкреНрд░рддрд┐рдпреЛрдЧрд┐рдпреЛрдВ рдХреЗ рдЦрд┐рд▓рд╛рдл рдЬреАрддрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, GoCD рдХреЗ рд╕рд╛рде рдореЗрдореЛрд░реА рдЦрдкрдд рдХреА рддреБрд▓рдирд╛ (рдФрд░ рд╣рд╛рдБ, рдирд╛рдо рдХреЗ рдмрд╛рд╡рдЬреВрдж, рдпрд╣ рдПрдХ рдЬрд╛рд╡рд╛ рд╕рд┐рд╕реНрдЯрдо рд╣реИ):

buildbot:



GoCD:



рдПрдХ рдЕрд▓рдЧ рдкрд░реАрдХреНрд╖рд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреА рддреИрдирд╛рддреА рдФрд░ рд▓реЗрдЦрди рдЦреБрдж рдЖрдкрдХреЛ рд╢реБрд░реБрдЖрддреА рд╕реЗрдЯрдЕрдк рдХреЗ рд╡рд┐рдЪрд╛рд░ рд╕реЗ рджреБрдЦреА рдХрд░ рд╕рдХрддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдХрдХреНрд╖рд╛рдУрдВ рдХреА рд╕рд░рд╛рд╕рд░ рд╕рдВрдЦреНрдпрд╛ рд╕реЗ рд╕реНрдХреНрд░рд┐рдкреНрдЯрд┐рдВрдЧ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИред рдпреЗ рдХрдХреНрд╖рд╛рдПрдВ рдХрдИ рдорд╛рдирдХ рд╕рдВрдЪрд╛рд▓рди рдХреЛ рдХрд╡рд░ рдХрд░рддреА рд╣реИрдВ, рдЪрд╛рд╣реЗ рдЗрд╕реЗ рдЧрд┐рдЯрдм рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдмрджрд▓рд╛рд╡ рдорд┐рд▓ рд░рд╣рд╛ рд╣реЛ рдпрд╛ рд╕реАрдПрдордХреЗ рдХреЗ рд╕рд╛рде рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рдирд╛ред рдирддреАрдЬрддрди, рдХреБрдЫ рдЯреНрд░реИрд╡рд┐рд╕-рд╕реАрдЖрдИ рдХреЗ рд▓рд┐рдП рд╡рд╛рдИрдПрдордПрд▓ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЫреЛрдЯреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдорд╛рдирдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реЛрдВрдЧреЗред рдореИрдВ рддреИрдирд╛рддреА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ рд▓рд┐рдЦреВрдВрдЧрд╛, рдпрд╣ рдореМрдЬреВрджрд╛ рд▓реЗрдЦреЛрдВ рдореЗрдВ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдХрд╡рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рд╡рд╣рд╛рдВ рдХреБрдЫ рднреА рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реИред

рдмрд┐рд▓реНрдбрдмреЙрдЯ рдХреА рдЕрдЧрд▓реА рд╡рд┐рд╢реЗрд╖рддрд╛, рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдкрд░реАрдХреНрд╖рдг рддрд░реНрдХ рдХреЛ ci-server рдХреЗ рдкрдХреНрд╖ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдЕрдм "рд▓реЛрдХрдкреНрд░рд┐рдп рдПрдХ рдХреЛрдб рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рдЗрдкрд▓рд╛рдЗрди" рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд▓рд┐рдП рдХрд╛рдЙрдВрдЯрд░ рдЪрд▓рд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рддрд░реНрдХ рдХреЛ рдПрдХ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ (рдЬреИрд╕реЗ .travis.yml) рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕реНрд░реЛрдд рдХреЛрдб рдХреЗ рд╕рд╛рде рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдкрдбрд╝рд╛ рд╣реБрдЖ рд╣реИ, рдФрд░ ci рд╕рд░реНрд╡рд░ рдХреЗрд╡рд▓ рдЗрд╕ рдлрд╝рд╛рдЗрд▓ рдХреЛ рдкрдврд╝рддрд╛ рд╣реИ рдФрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдХреНрдпрд╛ рдХрд╣рддрд╛ рд╣реИред рдлрд┐рд░, рдпрд╣ рдХреЗрд╡рд▓ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реИред рдмрд┐рд▓реНрдбрдмреЙрдЯ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреА рдХреНрд╖рдорддрд╛рдПрдВ рдЖрдкрдХреЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд╕рд╛рде рд╡рд░реНрдгрд┐рдд рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИрдВред рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдПрдХ рд░реЗрдбреА-рдореЗрдб рд╕рдорд╛рдзрд╛рди рднреА рд╣реИ - bb-travis , рдЬреЛ рдмрд┐рд▓реНрдбрдмреЙрдЯ рдФрд░ рдЯреНрд░реИрд╡рд┐рд╕-рд╕реАрдЖрдИ рд╕реЗ рд╕рд░реНрд╡рд╢реНрд░реЗрд╖реНрда рд▓реЗрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдмрд╛рдж рдореЗрдВ рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рд╡рд░реНрдгрди рдХрд░реВрдВрдЧрд╛ рдХрд┐ рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рд╕рдорд╛рди рдХреБрдЫ рдХреЛ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПред

рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдмрд┐рд▓реНрдбрдмреЛрдЯ рдкреБрд╢ рдХрд░рддреЗ рд╕рдордп рд╣рд░ рдХрдорд┐рдЯ рдПрдХрддреНрд░ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдХреБрдЫ рдЫреЛрдЯреЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдлреАрдЪрд░ рдХреА рддрд░рд╣ рд▓рдЧ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореЗрд░реЗ рд▓рд┐рдП, рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд, рдореБрдЦреНрдп рд▓рд╛рднреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдмрди рдЧрдпрд╛ рд╣реИред рдмреЙрдХреНрд╕ рдХреЗ рдмрд╛рд╣рд░ рдХрдИ рд▓реЛрдХрдкреНрд░рд┐рдп рд╕рдорд╛рдзрд╛рди (рдЯреНрд░реИрд╡рд┐рд╕-рд╕реА, рдЧрд┐рдЯрд▓реИрдм-рд╕реА) рдРрд╕рд╛ рдЕрд╡рд╕рд░ рдмрд┐рд▓реНрдХреБрд▓ рдирд╣реАрдВ рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВ, рдХреЗрд╡рд▓ рд╢рд╛рдЦрд╛ рдкрд░ рдЕрдВрддрд┐рдо рдкреНрд░рддрд┐рдмрджреНрдз рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдХрд▓реНрдкрдирд╛ рдХреАрдЬрд┐рдП рдХрд┐ рд╡рд┐рдХрд╛рд╕ рдХреЗ рджреМрд░рд╛рди рдЖрдкрдХреЛ рдЕрдХреНрд╕рд░ рдЪреЗрд░реА-рдкрд┐рдХ рдХрдорд┐рдЯ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИред рдпрд╣ рдПрдХ рдЧреИрд░-рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реА рдкреНрд░рддрд┐рдмрджреНрдз рд▓реЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкреНрд░рд┐рдп рд╣реЛрдЧрд╛, рдЬрд┐рд╕реЗ рдирд┐рд░реНрдорд╛рдг рдкреНрд░рдгрд╛рд▓реА рджреНрд╡рд╛рд░рд╛ рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рдирд╣реАрдВ рдЬрд╛рдВрдЪрд╛ рдЧрдпрд╛ рдерд╛ рдХрд┐ рдЗрд╕реЗ рдКрдкрд░ рд╕реЗ рдХрдорд┐рдЯреНрд╕ рдХреЗ рдПрдХ рдЭреБрдВрдб рдХреЗ рд╕рд╛рде рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдмреЗрд╢рдХ, рдмрд┐рд▓реНрдбрдмреЙрдЯ рдореЗрдВ рдЖрдк рдХреЗрд╡рд▓ рдЕрдВрддрд┐рдо рдХрдорд┐рдЯ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд╕реЗрдЯ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдлреНрд░реЗрдорд╡рд░реНрдХ рдореЗрдВ рдПрдХ рдХрд╛рдлреА рдЕрдЪреНрдЫрд╛ рджрд╕реНрддрд╛рд╡реЗрдЬ рд╣реИ, рдЬреЛ рд╕рд╛рдорд╛рдиреНрдп рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рд╕реЗ рд▓реЗрдХрд░ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд╡рд┐рд╕реНрддрд╛рд░ рдХреЗ рд▓рд┐рдП рджрд┐рд╢рд╛рдирд┐рд░реНрджреЗрд╢реЛрдВ рддрдХ рд╕рдм рдХреБрдЫ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдмрддрд╛рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕ рддрд░рд╣ рдХреЗ рдкреНрд░рд▓реЗрдЦрди рдХреЗ рд╕рд╛рде, рдЖрдкрдХреЛ рд╕реНрд░реЛрдд рдХреЛрдб рдореЗрдВ рдХреБрдЫ рдЪреАрдЬреЛрдВ рдХреЛ рджреЗрдЦрдирд╛ рдкрдбрд╝ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ GPL v2 рд▓рд╛рдЗрд╕реЗрдВрд╕ рдХреЗ рддрд╣рдд рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЦреБрд▓рд╛ рд╣реИ рдФрд░ рдкрдврд╝рдиреЗ рдореЗрдВ рдЖрд╕рд╛рди рд╣реИред Minuses рдХреА - рдкреНрд░рд▓реЗрдЦрди рдХреЗрд╡рд▓ рдЕрдВрдЧреНрд░реЗрдЬреА рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИ, рд░реВрд╕реА рдореЗрдВ рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдмрд╣реБрдд рдХрдо рдЬрд╛рдирдХрд╛рд░реА рд╣реИред рдЙрдкрдХрд░рдг рдХрд▓ рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджрд┐рдпрд╛, рдЗрд╕рдХреА рдорджрдж рд╕реЗ рдЕрдЬрдЧрд░ , рд╡рд┐рдВрдбрд╢рд╛рд░реНрдХ , рдПрд▓рдПрд▓рд╡реАрдПрдо рдФрд░ рдХрдИ рдЕрдиреНрдп рдкреНрд░рд╕рд┐рджреНрдз рдкрд░рд┐рдпреЛрдЬрдирд╛рдПрдВ рдЗрдХрдЯреНрдареА рдХреА рдЬрд╛рддреА рд╣реИрдВред рдЕрдкрдбреЗрдЯ рд╕рд╛рдордиреЗ рдЖ рд░рд╣реЗ рд╣реИрдВ, рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрдИ рдбреЗрд╡рд▓рдкрд░реНрд╕ рджреНрд╡рд╛рд░рд╛ рд╕рдорд░реНрдерд┐рдд рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╡рд┐рд╢реНрд╡рд╕рдиреАрдпрддрд╛ рдФрд░ рд╕реНрдерд╛рдпрд┐рддреНрд╡ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


(рдкрд╛рдпрдерди рдмрд┐рд▓реНрдбрдмреЛрдЯ рд╣реЛрдордкреЗрдЬ)

Teormin


рдпрд╣ рд╣рд┐рд╕реНрд╕рд╛ рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рдврд╛рдВрдЪреЗ рдХреЗ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдкрд░ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдкреНрд░рд▓реЗрдЦрди рдХреЗ рдЕрдзреНрдпрд╛рдп рдХрд╛ рдПрдХ рдореБрдлреНрдд рдЕрдиреБрд╡рд╛рдж рд╣реИред рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдкрд░рд┐рдгрд╛рдо рдХреА рд╕реВрдЪрдирд╛ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП ci-system рджреНрд╡рд╛рд░рд╛ рдкрд░рд┐рд╡рд░реНрддрди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╕реЗ рд▓реЗрдХрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреА рдкреВрд░реА рд╢реНрд░реГрдВрдЦрд▓рд╛ рджрд┐рдЦрд╛рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЖрдкрдиреЗ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд╕реНрд░реЛрдд рдХреЛрдб рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХрд┐рдП рдФрд░ рдЙрдиреНрд╣реЗрдВ рджреВрд░рд╕реНрде рднрдВрдбрд╛рд░ рдореЗрдВ рднреЗрдЬ рджрд┐рдпрд╛ред рдЖрдЧреЗ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ рдпрд╣ рдпреЛрдЬрдирд╛рдмрджреНрдз рд░реВрдк рд╕реЗ рдЪрд┐рддреНрд░ рдореЗрдВ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ:


( рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬ рд╕реЗ рддрд╕реНрд╡реАрд░)

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдмрд┐рд▓реНрдбрдмреЛрдЯ рдХреЛ рдХрд┐рд╕реА рддрд░рд╣ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдмрджрд▓рд╛рд╡ рд╣реБрдП рд╣реИрдВред рд╡рд╣рд╛рдБ рджреЛ рдореБрдЦреНрдп рддрд░реАрдХреЗ рд╣реИрдВ - webhooks рдФрд░ рдорддрджрд╛рди, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдХреЛрдИ рднреА рдЕрдзрд┐рдХ рдкрд░рд┐рд╖реНрдХреГрдд рдХреБрдЫ рдХреЗ рд╕рд╛рде рдЖрдиреЗ рд╕реЗ рдордирд╛ рдХрд░рддрд╛ рд╣реИред рдкрд╣рд▓реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдмрд┐рд▓реНрдбрдмреЙрдЯ рдореЗрдВ, рдмреЗрд╕рд╣реБрдХрд╣реИрдВрдбрд▓рд░ рд╡рдВрд╢рдЬ рд╡рд░реНрдЧ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИрдВред рдХрдИ рддреИрдпрд╛рд░ рд╕рдорд╛рдзрд╛рди рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, GitHubHandler рдпрд╛ GitoriusHandler ред рдЗрди рд╡рд░реНрдЧреЛрдВ рдореЗрдВ рдореБрдЦреНрдп рд╡рд┐рдзрд┐ getChanges () рд╣реИ ред рдЗрд╕рдХрд╛ рддрд░реНрдХ рдЕрддреНрдпрдВрдд рд╕рд░рд▓ рд╣реИ: рдЗрд╕реЗ HTTP рдЕрдиреБрд░реЛрдз рдХреЛ рдкрд░рд┐рд╡рд░реНрддрдирд╢реАрд▓ рд╡рд╕реНрддреБрдУрдВ рдХреА рд╕реВрдЪреА рдореЗрдВ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рд┐рдПред

рджреВрд╕рд░реЗ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкреЛрд▓рд┐рдВрдЧрдХреНрд░реЙрд╕рд╕реЛрд░реНрд╕ рдЕрд╡рд░реЛрд╣реА рд╡рд░реНрдЧреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдлрд┐рд░ рд╕реЗ, рддреИрдпрд╛рд░ рдХрд┐рдП рдЧрдП рд╕рдорд╛рдзрд╛рди рд╣реИрдВ, рдЬреИрд╕реЗ рдХрд┐ GitPoller рдпрд╛ HgPoller ред рдкреНрд░рдореБрдЦ рд╡рд┐рдзрд┐ рдкреЛрд▓ () рд╣реИ ред рдпрд╣ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдЖрд╡реГрддреНрддрд┐ рдХреЗ рд╕рд╛рде рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдХрд┐рд╕реА рддрд░рд╣ рднрдВрдбрд╛рд░ рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХреА рдПрдХ рд╕реВрдЪреА рдмрдирд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЧрд┐рдЯ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рднреНрд░реВрдг рд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдкрд┐рдЫрд▓реЗ рд╕рд╣реЗрдЬреЗ рдЧрдП рд░рд╛рдЬреНрдп рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдпрджрд┐ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдХреНрд╖рдорддрд╛рдПрдВ рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдмрд╕ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЙрддреНрддрд░рд╛рдзрд┐рдХрд╛рд░реА рд╡рд░реНрдЧ рдмрдирд╛рдПрдВ рдФрд░ рд╡рд┐рдзрд┐ рдХреЛ рдЕрдзрд┐рднрд╛рд░рд┐рдд рдХрд░реЗрдВред рдорддрджрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг:

c['change_source'] = [changes.GitPoller( repourl = 'git@git.example.com:project', project = 'My Project', branches = True, #      pollInterval = 60 )] 

Webhook рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдФрд░ рднреА рдЖрд╕рд╛рди рд╣реИ, рдореБрдЦреНрдп рдмрд╛рдд рдпрд╣ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЗрд╕реЗ git-server рдкрдХреНрд╖ рдкрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рднреВрд▓ рдЬрд╛рдПред рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдкрдВрдХреНрддрд┐ рд╣реИ:

 c['www']['change_hook_dialects'] = { 'github': {} } 

рдЕрдЧрд▓рд╛ рдЪрд░рдг, рдкрд░рд┐рд╡рд░реНрддрди рдСрдмреНрдЬреЗрдХреНрдЯ рд╢реЗрдбреНрдпреВрд▓рд░ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ ( рд╢реЗрдбреНрдпреВрд▓рд░реНрд╕ ) рдкрд░ рдЗрдирдкреБрдЯ рд╣реИрдВред рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдЕрдиреБрд╕реВрдЪрд┐рдпреЛрдВ рдХреЗ рдЙрджрд╛рд╣рд░рдг: AnyBranchScheduler , NightlyScheduler , ForceScheduler , рдЖрджрд┐ред рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд╕реВрдЪрдХ рдЗрдирдкреБрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрди рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рдЙрди рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЛ change_filter рддрд░реНрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдирд┐рд░реНрдорд╛рддрд╛ рдореЗрдВ рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЖрдЙрдЯрдкреБрдЯ рдкрд░, рдирд┐рдпреЛрдЬрдХ рдмрд┐рд▓реНрдб рдЕрдиреБрд░реЛрдз рдмрдирд╛рддреЗ рд╣реИрдВред рдЕрдиреБрд╕реВрдЪрдХ рдмрд┐рд▓реНрдбрд░реЛрдВ рдХреЗ рддрд░реНрдХ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдмрд┐рд▓реНрдбрд░реЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИред

рдХреБрдЫ рдпреЛрдЬрдирд╛рдХрд╛рд░реЛрдВ рдХреЗ рдкрд╛рд╕ рдПрдХ рдореБрд╢реНрдХрд┐рд▓ рддрд░реНрдХ рд╣реИ, рдЬрд┐рд╕реЗ рдЯреНрд░реАрд╕реНрдЯреЗрдмрд▓рдЯреЗрдорд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ: рдЬрдм рдХреЛрдИ рдкрд░рд┐рд╡рд░реНрддрди рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╢реЗрдбреНрдпреВрд▓рд░ рддреБрд░рдВрдд рдПрдХ рдирдпрд╛ рдмрд┐рд▓реНрдб рдЕрдиреБрд░реЛрдз рдирд╣реАрдВ рдмрдирд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЯрд╛рдЗрдорд░ рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдирдП рдкрд░рд┐рд╡рд░реНрддрди рдЖрддреЗ рд╣реИрдВ рдФрд░ рдЯрд╛рдЗрдорд░ рдХреА рд╕рдордп рд╕реАрдорд╛ рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рд╣реБрдИ рд╣реИ, рддреЛ рдкреБрд░рд╛рдиреЗ рдкрд░рд┐рд╡рд░реНрддрди рдХреЛ рдПрдХ рдирдП рд╕реЗ рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЯрд╛рдЗрдорд░ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЬрдм рдЯрд╛рдЗрдорд░ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рд╢реЗрдбреНрдпреВрд▓рд░ рдЕрдВрддрд┐рдо рд╕рд╣реЗрдЬреЗ рдЧрдП рдкрд░рд┐рд╡рд░реНрддрди рд╕реЗ рдХреЗрд╡рд▓ рдПрдХ рдмрд┐рд▓реНрдб рдЕрдиреБрд░реЛрдз рдмрдирд╛рддрд╛ рд╣реИред

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЬрдм рдзрдХреНрдХрд╛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддреЛ рдХреЗрд╡рд▓ рдЕрдВрддрд┐рдо рдкреНрд░рддрд┐рдмрджреНрдз рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд░рдиреЗ рдХрд╛ рддрд░реНрдХред рд╢реЗрдбреНрдпреВрд▓рд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдЙрджрд╛рд╣рд░рдг:

 c['schedulers'] = [schedulers.AnyBranchScheduler( name = 'My Scheduler', treeStableTimer = None, change_filter = util.ChangeFilter(project = 'My Project'), builderNames = ['My Builder'] )] 

рдмрд┐рд▓реНрдб рдЕрдиреБрд░реЛрдз, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЕрдЬреАрдм рд▓рдЧ рд╕рдХрддрд╛ рд╣реИ, рдмрд┐рд▓реНрдбрд░реЛрдВ рдХреЗ рдЗрдирдкреБрдЯ рдкрд░ рдЬрд╛рдПрдВред рдХрд▓реЗрдХреНрдЯрд░ рдХрд╛ рдХрд╛рд░реНрдп рдПрдХ рд╕реБрд▓рдн "рдХрд╛рд░реНрдпрдХрд░реНрддрд╛" рдкрд░ рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдХреЛ рдЪрд▓рд╛рдирд╛ рд╣реИред рд╡рд░реНрдХрд░ рдПрдХ рдирд┐рд░реНрдорд╛рдг рдкрд░рд┐рд╡реЗрд╢ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐ рдЦрд┐рдВрдЪрд╛рд╡ 64 рдпрд╛ ubuntu1804x64ред рд╢реНрд░рдорд┐рдХреЛрдВ рдХреА рд╕реВрдЪреА рдХреЛ рд╢реНрд░рдорд┐рдХ рддрд░реНрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕реВрдЪреА рдореЗрдВ рд╕рднреА рд╢реНрд░рдорд┐рдХреЛрдВ рдХреЛ рд╕рдорд╛рди рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП (рдпрд╛рдиреА рдирд╛рдо рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ рдЕрд▓рдЧ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЕрдВрджрд░ рдХрд╛ рд╡рд╛рддрд╛рд╡рд░рдг рд╕рдорд╛рди рд╣реИ), рдХреНрдпреЛрдВрдХрд┐ рдХрд▓реЗрдХреНрдЯрд░ рдХрд┐рд╕реА рднреА рдЙрдкрд▓рдмреНрдз рдХреЛ рдЪреБрдирдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рддрдВрддреНрд░ рд╣реИред рдпрд╣рд╛рдВ рдХрдИ рдорд╛рди рд╕реЗрдЯ рдХрд░рдирд╛ рд▓реЛрдб рдХреЛ рд╕рдВрддреБрд▓рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рди рдХрд┐ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рдирд┐рд░реНрдорд╛рдг рдХрд░рдиреЗ рдХрд╛ред рдХрд╛рд░рдХ y рддрд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдХрд▓реЗрдХреНрдЯрд░ рдХреЛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рдЪрд░рдгреЛрдВ рдХрд╛ рдЕрдиреБрдХреНрд░рдо рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИред рдореИрдВ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдиреАрдЪреЗ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд▓рд┐рдЦреВрдВрдЧрд╛ред

рдХрд▓реЗрдХреНрдЯрд░ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг:

 c['builders'] = [util.BuilderConfig( name = 'My Builder', workernames = ['stretch32'], factory = factory )] 

рддреЛ, рдкрд░рд┐рдпреЛрдЬрдирд╛ рддреИрдпрд╛рд░ рд╣реИред рдмрд┐рд▓реНрдбрдмреЙрдЯ рдХрд╛ рдЕрдВрддрд┐рдо рдЪрд░рдг рдмрд┐рд▓реНрдб рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рдирд╛ рд╣реИред рдЗрд╕рдХреЗ рд▓рд┐рдП рд░рд┐рдкреЛрд░реНрдЯрд░ рд╡рд░реНрдЧ рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИрдВред рдПрдХ рдХреНрд▓рд╛рд╕рд┐рдХ рдЙрджрд╛рд╣рд░рдг MailNotifier class рд╣реИ, рдЬреЛ рдмрд┐рд▓реНрдб рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдИрдореЗрд▓ рднреЗрдЬрддрд╛ рд╣реИред MailNotifier рдХрдиреЗрдХреНрд╢рди рдЙрджрд╛рд╣рд░рдг :

 c['services'] = [reporters.MailNotifier( fromaddr = 'buildbot@example.com', relayhost = 'mail.example.com', smtpPort = 25, extraRecipients = ['devel@example.com'], sendToInterestedUsers = False )] 

рдЦреИрд░, рдпрд╣ рд╕рдордп рд╣реИ рдХрд┐ рдкреВрд░реНрдг рд╡рд┐рдХрд╕рд┐рдд рдЙрджрд╛рд╣рд░рдгреЛрдВ рдкрд░ рдЖрдЧреЗ рдмрдврд╝реЗрдВред рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рдмрд┐рд▓реНрдбрдмреЙрдЯ рдЦреБрдж рдЯреНрд╡рд┐рд╕реНрдЯреЗрдб рдлреНрд░реЗрдорд╡рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рдЗрд╕рд▓рд┐рдП рдЗрд╕рдХреЗ рд╕рд╛рде рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдиреЗ рд╕реЗ рдмрд┐рд▓реНрдбрдмреЙрдЯ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓реЗрдЦрди рдФрд░ рд╕рдордЭ рдореЗрдВ рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛ рд╣реЛрдЧреАред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкреЗрдЯ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдирд╛рдордХ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдЪреЗрддрдХ рд▓рдбрд╝рдХрд╛ рд╣реЛрдЧрд╛ред рдЗрд╕реЗ рд╕реА ++ рдореЗрдВ рд▓рд┐рдЦрд╛ рдЬрд╛рдП, рд╕реАрдПрдордХреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдФрд░ рд╕реНрд░реЛрдд рдХреЛрдб рдЧрд┐рдЯ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдирд┐рд╣рд┐рдд рд╣реИред рд╣рдо рдмрд╣реБрдд рдЖрд▓рд╕реА рдирд╣реАрдВ рдереЗ рдФрд░ рдЙрдирдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦреЗ рдЬреЛ рдХрд┐ ctest рдЯреАрдо рджреНрд╡рд╛рд░рд╛ рдЪрд▓рд╛рдП рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред рд╣рд╛рд▓ рд╣реА рдореЗрдВ, рд╣рдордиреЗ рдЗрд╕ рд▓реЗрдЦ рдХреЛ рдкрдврд╝рд╛ рдФрд░ рдорд╣рд╕реВрд╕ рдХрд┐рдпрд╛ рдХрд┐ рд╣рдо рдЕрдкрдиреА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдирдП рд╕рд┐рд░реЗ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдЬреНрдЮрд╛рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред

рдЙрджрд╛рд╣рд░рдг рдПрдХ: рдЗрд╕рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рдирд╛ рд╣реИ


рджрд░рдЕрд╕рд▓, рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓:

рдЕрдЬрдЧрд░ рдХреЛрдб рдХреА 100 рд▓рд╛рдЗрдиреЗрдВ
 from buildbot.plugins import * # shortcut c = BuildmasterConfig = {} # create workers c['workers'] = [worker.Worker('stretch32', 'example_password')] # general settings c['title'] = 'Buildbot: test' c['titleURL'] = 'https://buildbot.example.com/' c['buildbotURL'] = 'https://buildbot.example.com/' # setup database c['db'] = { 'db_url': 'sqlite:///state.sqlite' } # port to communicate with workers c['protocols'] = { 'pb': { 'port': 9989 } } # make buildbot developers a little bit happier c['buildbotNetUsageData'] = 'basic' # webserver setup c['www'] = dict(plugins = dict(waterfall_view={}, console_view={}, grid_view={})) c['www']['authz'] = util.Authz( allowRules = [util.AnyEndpointMatcher(role = 'admins')], roleMatchers = [util.RolesFromUsername(roles = ['admins'], usernames = ['root'])] ) c['www']['auth'] = util.UserPasswordAuth([('root', 'root_password')]) # mail notification c['services'] = [reporters.MailNotifier( fromaddr = 'buildbot@example.com', relayhost = 'mail.example.com', smtpPort = 25, extraRecipients = ['devel@example.com'], sendToInterestedUsers = False )] c['change_source'] = [changes.GitPoller( repourl = 'git@git.example.com:pet-project', project = 'Pet Project', branches = True, pollInterval = 60 )] c['schedulers'] = [schedulers.AnyBranchScheduler( name = 'Pet Project Scheduler', treeStableTimer = None, change_filter = util.ChangeFilter(project = 'Pet Project'), builderNames = ['Pet Project Builder'] )] factory = util.BuildFactory() factory.addStep(steps.Git( repourl = util.Property('repository'), workdir = 'sources', haltOnFailure = True, submodules = True, progress = True) ) factory.addStep(steps.ShellSequence( name = 'create builddir', haltOnFailure = True, hideStepIf = lambda results, s: results == util.SUCCESS, commands = [ util.ShellArg(command = ['rm', '-rf', 'build']), util.ShellArg(command = ['mkdir', 'build']) ]) ) factory.addStep(steps.CMake( workdir = 'build', path = '../sources', haltOnFailure = True) ) factory.addStep(steps.Compile( name = 'build project', workdir = 'build', haltOnFailure = True, warnOnWarnings = True, command = ['make']) ) factory.addStep(steps.ShellCommand( name = 'run tests', workdir = 'build', haltOnFailure = True, command = ['ctest']) ) c['builders'] = [util.BuilderConfig( name = 'Pet Project Builder', workernames = ['stretch32'], factory = factory )] 


рдЗрди рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд▓рд┐рдЦрдХрд░ рд╣рдо рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА, рдПрдХ рд╕реБрдВрджрд░ рд╡реЗрдм рдлреЗрд╕, рдИрдореЗрд▓ рдиреЛрдЯрд┐рдлрд┐рдХреЗрд╢рди рдФрд░ рдХрд┐рд╕реА рднреА рд╕реНрд╡рд╛рднрд┐рдорд╛рдиреА рд╕реАрдЖрдИ рдХреА рдЕрдиреНрдп рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдкрд░ рдЬреЛрд░ рджреЗрддреЗ рд╣реБрдП рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдЕрд╕реЗрдВрдмрд▓реА рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рдореЗрдВ рд╕реЗ рдЕрдзрд┐рдХрд╛рдВрд╢ рд╕реНрдкрд╖реНрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП: рдЕрдиреБрд╕реВрдЪрд┐рдпреЛрдВ, рдХрд▓реЗрдХреНрдЯрд░реЛрдВ рдФрд░ рдЕрдиреНрдп рд╡рд╕реНрддреБрдУрдВ рдХреА рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдкрд╣рд▓реЗ рджрд┐рдП рдЧрдП рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд╕рдорд╛рди рд╣реИрдВ, рдЕрдзрд┐рдХрд╛рдВрд╢ рдорд╛рдкрджрдВрдбреЛрдВ рдХрд╛ рдореВрд▓реНрдп рд╕рд╣рдЬ рд╣реИред рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ, рдореИрдВ рдХреЗрд╡рд▓ рдПрдХ рдХрд╛рд░рдЦрд╛рдирд╛ рдмрдирд╛рдиреЗ рдкрд░ рдзреНрдпрд╛рди рджреВрдВрдЧрд╛, рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдкрд╣рд▓реЗ рдХрд░рдиреЗ рдХрд╛ рд╡рд╛рджрд╛ рдХрд┐рдпрд╛ рдерд╛ред

рдХрд╛рд░рдЦрд╛рдиреЗ рдореЗрдВ рдмрд┐рд▓реНрдб рдХрджрдо рд╣реЛрддреЗ рд╣реИрдВ рдЬреЛ рдмрд┐рд▓реНрдбрдмреЛрдЯ рдХреЛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП рдкреВрд░рд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЕрдиреНрдп рд╡рд░реНрдЧреЛрдВ рдХреЗ рд╕рд╛рде рдХреЗ рд░реВрдк рдореЗрдВ, рдХрдИ рддреИрдпрд╛рд░ рд╕рдорд╛рдзрд╛рди рд╣реИрдВред рд╣рдорд╛рд░реЗ рдХрд╛рд░рдЦрд╛рдиреЗ рдкрд╛рдВрдЪ рдЪрд░рдгреЛрдВ рдХреЗ рд╣реЛрддреЗ рд╣реИрдВред рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рдкрд╣рд▓рд╛ рдХрджрдо рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреА рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╣реИ, рдФрд░ рдпрд╣рд╛рдВ рд╣рдо рдЕрдкрд╡рд╛рдж рдирд╣реАрдВ рдмрдирд╛рдПрдВрдЧреЗред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдорд╛рдирдХ Git рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ:

рдкрд╣рд▓рд╛ рдХрджрдо
 factory = util.BuildFactory() factory.addStep(steps.Git( repourl = util.Property('repository'), workdir = 'sources', haltOnFailure = True, submodules = True, progress = True) ) 


рдЕрдЧрд▓рд╛, рд╣рдореЗрдВ рдПрдХ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ - рд╣рдо рдПрдХ рдкреВрд░реНрдг рдирд┐рд░реНрдорд╛рдг рд╕реНрд░реЛрдд рдмрдирд╛рдПрдВрдЧреЗред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ, рдЖрдкрдХреЛ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреЛ рд╣рдЯрд╛рдирд╛ рдпрд╛рдж рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП рдпрджрд┐ рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рдореМрдЬреВрдж рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдореЗрдВ рджреЛ рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред ShellSequence рд╡рд░реНрдЧ рд╣рдореЗрдВ рдЗрд╕рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛:

рджреВрд╕рд░рд╛ рдХрджрдо
 factory.addStep(steps.ShellSequence( name = 'create builddir', haltOnFailure = True, hideStepIf = lambda results, s: results == util.SUCCESS, commands = [ util.ShellArg(command = ['rm', '-rf', 'build']), util.ShellArg(command = ['mkdir', 'build']) ]) ) 


рдЕрдм рдЖрдкрдХреЛ рд╕реАрдПрдордХреЗ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рджреЛ рд╡рд░реНрдЧреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рддрд░реНрдХрд╕рдВрдЧрдд рд╣реИ - рд╢реЗрд▓рдХреЛрдореИрдВрдб рдпрд╛ рд╕реАрдореЗрдХ ред рд╣рдо рдмрд╛рдж рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рд▓реЗрдХрд┐рди рдЕрдВрддрд░ рдиреНрдпреВрдирддрдо рд╣реИрдВ: рдпрд╣ рдкреНрд░рдердо рд╢реНрд░реЗрдгреА рдкрд░ рдПрдХ рд╕рд░рд▓ рдЖрд╡рд░рдг рд╣реИ , рдЬреЛ рд╕реАрдПрдордХреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢рд┐рд╖реНрдЯ рддрд░реНрдХ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдмрдирд╛рддрд╛ рд╣реИред

рддреАрд╕рд░рд╛ рдХрджрдо
 factory.addStep(steps.CMake( workdir = 'build', path = '../sources', haltOnFailure = True) ) 


рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдХрд╛ рд╕рдордпред рдкрд┐рдЫрд▓реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрдк рд╢реЗрд▓рдХреЛрдореИрдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕реА рддрд░рд╣, рдХрдВрдкрд╛рдЗрд▓ рдХреНрд▓рд╛рд╕ рд╣реИ, рдЬреЛ рд╢реЗрд▓рдХреЛрдореИрдВрдб рдХреЗ рдКрдкрд░ рдПрдХ рдЖрд╡рд░рдг рд╣реИред рдлрд┐рд░ рднреА, рдпрд╣ рдПрдХ рдкреЗрдЪреАрджрд╛ рдЖрд╡рд░рдг рд╣реИ: рд╕рдВрдХрд▓рди рдХреЗ рджреМрд░рд╛рди рд╕рдВрдХрд▓рди рдХреНрд▓рд╛рд╕ рдореЙрдирд┐рдЯрд░рд┐рдВрдЧ рдЪреЗрддрд╛рд╡рдирд┐рдпреЛрдВ рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдПрдХ рдЕрд▓рдЧ рд▓реЙрдЧ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд╣рдо рдХрдореНрдкрд╛рдЗрд▓ рдХреНрд▓рд╛рд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ:

рдЪреМрдерд╛ рдЪрд░рдг
 factory.addStep(steps.Compile( name = 'build project', workdir = 'build', haltOnFailure = True, warnOnWarnings = True, command = ['make']) ) 


рдЕрдВрдд рдореЗрдВ, рд╣рдорд╛рд░реЗ рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдПрдВред рдпрд╣рд╛рдВ рд╣рдо рдкрд╣рд▓реЗ рдмрддрд╛рдП рдЧрдП ShellCommand рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ:

рдкрд╛рдВрдЪрд╡рд╛рдВ рдЪрд░рдг
 factory.addStep(steps.ShellCommand( name = 'run tests', workdir = 'build', haltOnFailure = True, command = ['ctest']) ) 


рдЙрджрд╛рд╣рд░рдг рджреЛ: рдПрдХ рдХреЛрдб рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рдЗрдкрд▓рд╛рдЗрди


рдпрд╣рд╛рдВ рдореИрдВ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд▓реЙрдЬрд┐рдХ рдХреЛрдб рдХреЗ рд╕рд╛рде рдЯреЗрд╕реНрдЯрд┐рдВрдЧ рд▓реЙрдЬрд┐рдХ рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдЬрдЯ рд╡рд┐рдХрд▓реНрдк рдХреЛ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдП, рди рдХрд┐ ci-server рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╛рдЗрд▓ рдореЗрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХреЛрдб рдХреЗ рд╕рд╛рде рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ .buildbot рдлрд╝рд╛рдЗрд▓ рдбрд╛рд▓реЗрдВ , рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рд╢рдмреНрдж рд╢рд╛рдорд┐рд▓ рд╣реИрдВ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкрд╣рд▓реА рдХреЛ рдХрдорд╛рдВрдб рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдПрдХ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХреА рдЧрдИ рд╣реИ, рдФрд░ рдмрд╛рдХреА рдЕрдкрдиреЗ рддрд░реНрдХреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдХрдорд╛рдВрдб рдХреЗ рд░реВрдк рдореЗрдВред рд╣рдорд╛рд░реЗ рдкреЗрдЯ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП .buildbot рдлрд╛рдЗрд▓ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧреА:

рдХрдорд╛рдВрдб рдХреЗ рд╕рд╛рде .Bildbot рдлрд╝рд╛рдЗрд▓
. rm -rf build
. mkdir build
build cmake ../sources
build make
build ctest


рдЕрдм рд╣рдореЗрдВ рдмрд┐рд▓реНрдбрдмреЛрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред .Buildbot рдлрд╛рдЗрд▓ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЪрд░рдг рдХреА рдПрдХ рдХрдХреНрд╖рд╛ рд▓рд┐рдЦрдиреА рд╣реЛрдЧреАред рдпрд╣ рдЪрд░рдг .buildbot рдлрд╝рд╛рдЗрд▓ рдХреЛ рдкрдврд╝реЗрдЧрд╛ , рдЬрд┐рд╕рдХреЗ рдмрд╛рдж рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рддрд░реНрдХ рдХреЗ рд╕рд╛рде ShellCommand рдЪрд░рдг рдЬреЛрдбрд╝реЗрдВред рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЪрд░рдг рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо build.addStepsAfterCurrentStep () рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рдбрд░рд╛рд╡рдирд╛ рдирд╣реАрдВ рд╣реИ:

рдХреНрд▓рд╛рд╕ рдПрдирд╛рд▓рд┐рд╕рд┐рд╕рд╕реНрдЯреЗрдк
 class AnalyseStep(ShellMixin, BuildStep): def __init__(self, workdir, **kwargs): kwargs = self.setupShellMixin(kwargs, prohibitArgs = ['command', 'workdir', 'want_stdout']) BuildStep.__init__(self, **kwargs) self.workdir = workdir @defer.inlineCallbacks def run(self): self.stdio_log = yield self.addLog('stdio') cmd = RemoteShellCommand( command = ['cat', '.buildbot'], workdir = self.workdir, want_stdout = True, want_stderr = True, collectStdout = True ) cmd.useLog(self.stdio_log) yield self.runCommand(cmd) if cmd.didFail(): defer.returnValue(util.FAILURE) results = [] for row in cmd.stdout.splitlines(): lst = row.split() dirname = lst.pop(0) results.append(steps.ShellCommand( name = lst[0], command = lst, workdir = dirname ) ) self.build.addStepsAfterCurrentStep(results) defer.returnValue(util.SUCCESS) 


рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдХрд▓реЗрдХреНрдЯрд░ рдХреЗ рд▓рд┐рдП рдХрд╛рд░рдЦрд╛рдирд╛ рд╕рд░рд▓ рдФрд░ рдЕрдзрд┐рдХ рдмрд╣реБрдореБрдЦреА рд╣реЛ рдЧрдпрд╛ рд╣реИ:

рдлрд╝рд╛рдЗрд▓ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлреИрдХреНрдЯрд░реА
 factory = util.BuildFactory() factory.addStep(steps.Git( repourl = util.Property('repository'), workdir = 'sources', haltOnFailure = True, submodules = True, progress = True, mode = 'incremental') ) factory.addStep(AnalyseStep( name = 'Analyse .buildbot file', workdir = 'sources', haltOnFailure = True, hideStepIf = lambda results, s: results == util.SUCCESS) ) 


рдЙрджрд╛рд╣рд░рдг рддреАрди: рдПрдХ рдХреЛрдб рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛


рдЕрдм рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛрдб рдХреЗ рдмрдЧрд▓ рдореЗрдВ, рд╣рдореЗрдВ рдЖрджреЗрд╢реЛрдВ рдХреЗ рдЕрдиреБрдХреНрд░рдо рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдХреЗ рд▓рд┐рдП рд╡рд╛рддрд╛рд╡рд░рдгред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдо рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред .Buildbot рдлрд╛рдЗрд▓ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦ рд╕рдХрддреА рд╣реИ:

ред рдкрд░реНрдпрд╛рд╡рд░рдг рдХреА рдлрд╝рд╛рдЗрд▓
{
"workers": ["stretch32", "wheezy32"]
}


рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдмрд┐рд▓реНрдбрдмреЛрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реЛ рдЬрд╛рдПрдЧреА, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рд╡рд┐рднрд┐рдиреНрди рдкрд░рд┐рд╡реЗрд╢реЛрдВ рдкрд░ рдЕрд╕реЗрдВрдмрд▓реА рдХреЛ рдкрд░рд╕реНрдкрд░ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдП (рдпрджрд┐ рдХрдо рд╕реЗ рдХрдо рдПрдХ рд╡рд╛рддрд╛рд╡рд░рдг рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдкреВрд░реА рдкреНрд░рддрд┐рдмрджреНрдзрддрд╛ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдорд╛рдиреА рдЧрдИ рдереА)ред рджреЛ-рд╕реНрддрд░реАрдп рд╣рдореЗрдВ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╕реНрдерд╛рдиреАрдп рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рд╣реЛрдЧрд╛ рдЬреЛ .buildbot рдлрд╛рдЗрд▓ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╡рд╛рдВрдЫрд┐рдд рд╢реНрд░рдорд┐рдХреЛрдВ рдкрд░ рдмрд┐рд▓реНрдб рдЪрд▓рд╛рддрд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рдХреА рддрд░рд╣, рд╣рдо .buildbot рдлрд╛рдЗрд▓ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рдЪрд░рдг рд▓рд┐рдЦреЗрдВрдЧреЗ ред рдХрд┐рд╕реА рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдкрд░ рдЕрд╕реЗрдВрдмрд▓реА рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЯреНрд░рд┐рдЧрд░ рд╕реНрдЯреЗрдк рд╕реЗ рдПрдХ рдмрдВрдбрд▓ рдФрд░ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдкреНрд░рдХрд╛рд░ рдХреЗ рдЯреНрд░рд┐рдЧрд░реНрдЬреЗрдмрд▓ рд╢реЗрдбреНрдпреВрд▓рд░ рд╢реЗрдбреНрдпреВрд▓рд░реНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ред рд╣рдорд╛рд░рд╛ рдХрджрдо рдереЛрдбрд╝рд╛ рдФрд░ рдЬрдЯрд┐рд▓ рд╣реЛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХрд╛рдлреА рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ:

рдХреНрд▓рд╛рд╕ рдПрдирд╛рд▓рд┐рд╕рд┐рд╕рд╕реНрдЯреЗрдк
 class AnalyseStep(ShellMixin, BuildStep): def __init__(self, workdir, **kwargs): kwargs = self.setupShellMixin(kwargs, prohibitArgs = ['command', 'workdir', 'want_stdout']) BuildStep.__init__(self, **kwargs) self.workdir = workdir @defer.inlineCallbacks def _getWorkerList(self): cmd = RemoteShellCommand( command = ['cat', '.buildbot'], workdir = self.workdir, want_stdout = True, want_stderr = True, collectStdout = True ) cmd.useLog(self.stdio_log) yield self.runCommand(cmd) if cmd.didFail(): defer.returnValue([]) # parse JSON try: payload = json.loads(cmd.stdout) workers = payload.get('workers', []) except json.decoder.JSONDecodeError as e: raise ValueError('Error loading JSON from .buildbot file: {}' .format(str(e))) defer.returnValue(workers) @defer.inlineCallbacks def run(self): self.stdio_log = yield self.addLog('stdio') try: workers = yield self._getWorkerList() except ValueError as e: yield self.stdio_log.addStdout(str(e)) defer.returnValue(util.FAILURE) results = [] for worker in workers: results.append(steps.Trigger( name = 'check on worker "{}"'.format(worker), schedulerNames = ['Pet Project ({}) Scheduler'.format(worker)], waitForFinish = True, haltOnFailure = True, warnOnWarnings = True, updateSourceStamp = False, alwaysUseLatest = False ) ) self.build.addStepsAfterCurrentStep(results) defer.returnValue(util.SUCCESS) 


рд╣рдо рд╕реНрдерд╛рдиреАрдп рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдХреЗ рдЗрд╕ рдХрджрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдордиреЗ рдЕрдкрдиреЗ рдХрд▓реЗрдХреНрдЯрд░ "рдкреЗрдЯ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрд┐рд▓реНрдбрд░" рдХреЛ рдЯреИрдЧ рд╕реЗрдЯ рдХрд░ рджрд┐рдпрд╛ рд╣реИред рдЗрд╕рдХреЗ рд╕рд╛рде, рд╣рдо рдореЗрд▓рдиреЛрдЯрд┐рдлрд╛рдпрд░ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╣ рдмрддрд╛рддреЗ рд╣реБрдП рдХрд┐ рдкрддреНрд░ рдХреЗрд╡рд▓ рдХреБрдЫ рдХрд▓реЗрдХреНрдЯрд░реЛрдВ рдХреЛ рднреЗрдЬреЗ рдЬрд╛рдиреЗ рдЪрд╛рд╣рд┐рдПред рдпрджрд┐ рдпрд╣ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рджреЛ рд╡рд╛рддрд╛рд╡рд░рдгреЛрдВ рдкрд░ рдкреНрд░рддрд┐рдмрджреНрдз рдмрдирд╛рддреЗ рд╕рдордп, рд╣рдореЗрдВ рддреАрди рдкрддреНрд░ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдВрдЧреЗред

рд╕рд╛рдорд╛рдиреНрдп рдХрд▓реЗрдХреНрдЯрд░
 factory = util.BuildFactory() factory.addStep(steps.Git( repourl = util.Property('repository'), workdir = 'sources', haltOnFailure = True, submodules = True, progress = True, mode = 'incremental') ) factory.addStep(AnalyseStep( name = 'Analyse .buildbot file', workdir = 'sources', haltOnFailure = True, hideStepIf = lambda results, s: results == util.SUCCESS) ) c['builders'] = [util.BuilderConfig( name = 'Pet Project Builder', tags = ['generic_builder'], workernames = ['local'], factory = factory )] 


рдпрд╣ рд╣рдорд╛рд░реЗ рд╕рднреА рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╢реНрд░рдорд┐рдХреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд▓реЗрдХреНрдЯрд░реЛрдВ рдФрд░ рдПрдХ рд╣реА рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╢реЗрдбреНрдпреВрд▓рд░реНрд╕ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд░рд╣рддрд╛ рд╣реИ:

рд╕рд╣реА рдорд╛рд╣реМрд▓ рдореЗрдВ рдХрд▓реЗрдХреНрдЯрд░
 for worker in allWorkers: c['schedulers'].append(schedulers.Triggerable( name = 'Pet Project ({}) Scheduler'.format(worker), builderNames = ['Pet Project ({}) Builder'.format(worker)]) ) c['builders'].append(util.BuilderConfig( name = 'Pet Project ({}) Builder'.format(worker), workernames = [worker], factory = specific_factory) ) 



(рджреЛ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рдкреГрд╖реНрда рдмрдирд╛рдПрдБ)

рдЙрджрд╛рд╣рд░рдг рдЪрд╛рд░: рдХрдИ рдЕрдХреНрд╖рд░реЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдЕрдХреНрд╖рд░


рдпрджрд┐ рдЖрдк рдЙрдкрд░реЛрдХреНрдд рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ рд╕реЗ рдХрд┐рд╕реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдПрдХ рдЕрдкреНрд░рд┐рдп рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рдиреЛрдЯрд┐рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЪреВрдВрдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рддрд┐рдмрджреНрдз рдХреЗ рд▓рд┐рдП рдПрдХ рдкрддреНрд░ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрдм рд╣рдо рд╢рд╛рдЦрд╛ рдХреЛ 20 рдирдП рдХрдорд┐рдЯ рдХреЗ рд╕рд╛рде рдЖрдЧреЗ рдмрдврд╝рд╛рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ 20 рдкрддреНрд░ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдВрдЧреЗред рдЗрд╕рд╕реЗ рдмрдЪрддреЗ рд╣реБрдП, рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рдХреА рддрд░рд╣, рд╣рдо рджреЛ-рд╕реНрддрд░реАрдп рдорджрдж рдХрд░реЗрдВрдЧреЗред рд╣рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдХреНрд╖рд╛ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдХрдИ рдкрд░рд┐рд╡рд░реНрддрди рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рдХреЗрд╡рд▓ рдПрдХ рдРрд╕реА рд╡рд╕реНрддреБ рдмрдирд╛рдПрдВрдЧреЗ, рдЬрд┐рд╕рдХреЗ рдЧреБрдгреЛрдВ рдореЗрдВ рд╕рднреА рдХрдорд┐рдЯреНрд╕ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╕рд╛рд░рд┐рдд рд╣реЛрддреА рд╣реИред рдЬрд▓реНрджреА рдореЗрдВ, рдпрд╣ рдЗрд╕ рддрд░рд╣ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

рдХреНрд▓рд╛рд╕ рдорд▓реНрдЯреАрдЧрд┐рдЯрд╣реБрдмрдВрдбрд▓рд░
 class MultiGitHubHandler(GitHubHandler): def getChanges(self, request): new_changes = GitHubHandler.getChanges(self, request) if not new_changes: return ([], 'git') change = new_changes[-1] change['revision'] = '{}..{}'.format( new_changes[0]['revision'], new_changes[-1]['revision']) commits = [c['revision'] for c in new_changes] change['properties']['commits'] = commits return ([change], 'git') c['www']['change_hook_dialects'] = { 'base': { 'custom_class': MultiGitHubHandler } } 


рдЗрд╕ рддрд░рд╣ рдХреЗ рдЕрд╕рд╛рдорд╛рдиреНрдп рдкрд░рд┐рд╡рд░реНрддрди рд╡рд╛рд▓реА рд╡рд╕реНрддреБ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд╡рд┐рд╢реЗрд╖ рдХрджрдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЬреЛ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдРрд╕реЗ рдХрджрдо рдмрдирд╛рддрд╛ рд╣реИ рдЬреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рддрд┐рдмрджреНрдзрддрд╛ рдПрдХрддреНрд░ рдХрд░рддреЗ рд╣реИрдВ:

рдХрдХреНрд╖рд╛ GenerateCommitSteps
 class GenerateCommitSteps(BuildStep): def run(self): commits = self.getProperty('commits') results = [] for commit in commits: results.append(steps.Trigger( name = 'Checking commit {}'.format(commit), schedulerNames = ['Pet Project Commits Scheduler'], waitForFinish = True, haltOnFailure = True, warnOnWarnings = True, sourceStamp = { 'branch': util.Property('branch'), 'revision': commit, 'codebase': util.Property('codebase'), 'repository': util.Property('repository'), 'project': util.Property('project') } ) ) self.build.addStepsAfterCurrentStep(results) return util.SUCCESS 


рд╣рдорд╛рд░реЗ рд╕рд╛рдорд╛рдиреНрдп рд╕рдВрдЧреНрд░рд╛рд╣рдХ рдХреЛ рдЬреЛрдбрд╝реЗрдВ, рдЬреЛ рдХреЗрд╡рд▓ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдХрдорд┐рдЯрд┐рдпреЛрдВ рдХреА рд╡рд┐рдзрд╛рдирд╕рднрд╛рдУрдВ рдХреЛ рдЪрд▓рд╛рдиреЗ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реИред рддрдм рдЗрд╕ рдЯреИрдЧ рджреНрд╡рд╛рд░рд╛ рдЕрдХреНрд╖рд░реЛрдВ рдХреЗ рднреЗрдЬрдиреЗ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рдЯреИрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╕рд╛рдорд╛рдиреНрдп рдореЗрд▓ рдлрд╝реЗрдЪрд░
 c['schedulers'] = [schedulers.AnyBranchScheduler( name = 'Pet Project Branches Scheduler', treeStableTimer = None, change_filter = util.ChangeFilter(project = 'Pet Project'), builderNames = ['Pet Project Branches Builder'] )] branches_factory = util.BuildFactory() branches_factory.addStep(GenerateCommitSteps( name = 'Generate commit steps', haltOnFailure = True, hideStepIf = lambda results, s: results == util.SUCCESS) ) c['builders'] = [util.BuilderConfig( name = 'Pet Project Branches Builder', tags = ['branch_builder'], workernames = ['local'], factory = branches_factory )] 


рдпрд╣ рдХреЗрд╡рд▓ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдЖрд╡рд╛рдЧрдорди рдХреЗ рд▓рд┐рдП рдХрд▓реЗрдХреНрдЯрд░ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рд╣рдо рдЗрд╕ рдХрд▓реЗрдХреНрдЯрд░ рдХреЛ рдХреЗрд╡рд▓ рдПрдХ рдЯреИрдЧ рдХреЗ рд╕рд╛рде рдЯреИрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдЗрд╕рд▓рд┐рдП рдЗрд╕рдХреЗ рд▓рд┐рдП рдкрддреНрд░ рдирд╣реАрдВ рдмрдирд╛рдП рдЬрд╛рдПрдВрдЧреЗред

рд╕рд╛рдорд╛рдиреНрдп рдореЗрд▓ рдлрд╝реЗрдЪрд░
 c['schedulers'].append(schedulers.Triggerable( name = 'Pet Project Commits Scheduler', builderNames = ['Pet Project Commits Builder']) ) c['builders'].append(util.BuilderConfig( name = 'Pet Project Commits Builder', workernames = ['stretch32'], factory = specific_factory) ) 


рдЕрдВрддрд┐рдо рд╢рдмреНрдж


рдпрд╣ рд▓реЗрдЦ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдкреНрд░рд▓реЗрдЦрди рдХреЛ рдкрдврд╝рдиреЗ рдХреА рдЬрдЧрд╣ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдк рдмрд┐рд▓реНрдбрдмреЙрдЯ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХрд╛ рдЕрдЧрд▓рд╛ рдХрджрдо рдЗрд╕реЗ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╕рднреА рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рдкреВрд░реНрдг рд╕рдВрд╕реНрдХрд░рдг рдЬреАрдердм рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИрдВред рд╕рдВрдмрдВрдзрд┐рдд рд▓рд┐рдВрдХ, рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рд▓реЗрдЦ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХрд╛рдВрд╢ рд╕рд╛рдордЧреНрд░реА рд▓реА рдЧрдИ рдереА:

  1. рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬ
  2. рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд╕реЛрд░реНрд╕ рдХреЛрдб

Source: https://habr.com/ru/post/hi439096/


All Articles