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

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

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗред рдПрдХ рдкреНрд░рдпреЛрдЧрд╛рддреНрдордХ рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВрдиреЗ 2 рд╕рдорд╛рдкрди рдмрд┐рдВрджреБрдУрдВ рдХреЗ рд╕рд╛рде рдлреНрд▓рд╛рд╕реНрдХ рдкрд░ рдПрдХ рд╕рд░рд▓ рд╡реЗрдм рд╕рд░реНрд╡рд░ рд▓рд┐рдЦрд╛:
рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╡реЗрдм рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╕реВрдЪреАрдмрджреНрдз рдХрд░рдирд╛from flask import Flask from flask import request, jsonify app = Flask(__name__) def validate_post_data(data: dict) -> bool: if not isinstance(data, dict): return False if not data.get('name') or not isinstance(data['name'], str): return False if data.get('age') and not isinstance(data['age'], int): return False return True @app.route('/', methods=['GET']) def hello(): return 'Hello World!' @app.route('/api', methods=['GET', 'POST']) def api(): """ /api entpoint GET - returns json= {'status': 'test'} POST - { name - str not null age - int optional } :return: """ if request.method == 'GET': return jsonify({'status': 'test'}) elif request.method == 'POST': if validate_post_data(request.json): return jsonify({'status': 'OK'}) else: return jsonify({'status': 'bad input'}), 400 def main(): app.run(host='0.0.0.0', port=8080) if __name__ == '__main__': main()
рдФрд░ рдХреБрдЫ рдкрд░реАрдХреНрд╖рдг:
рдЖрд╡реЗрджрди рдкрд░реАрдХреНрд╖рдг рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ import unittest import app as tested_app import json class FlaskAppTests(unittest.TestCase): def setUp(self): tested_app.app.config['TESTING'] = True self.app = tested_app.app.test_client() def test_get_hello_endpoint(self): r = self.app.get('/') self.assertEqual(r.data, b'Hello World!') def test_post_hello_endpoint(self): r = self.app.post('/') self.assertEqual(r.status_code, 405) def test_get_api_endpoint(self): r = self.app.get('/api') self.assertEqual(r.json, {'status': 'test'}) def test_correct_post_api_endpoint(self): r = self.app.post('/api', content_type='application/json', data=json.dumps({'name': 'Den', 'age': 100})) self.assertEqual(r.json, {'status': 'OK'}) self.assertEqual(r.status_code, 200) r = self.app.post('/api', content_type='application/json', data=json.dumps({'name': 'Den'})) self.assertEqual(r.json, {'status': 'OK'}) self.assertEqual(r.status_code, 200) def test_not_dict_post_api_endpoint(self): r = self.app.post('/api', content_type='application/json', data=json.dumps([{'name': 'Den'}])) self.assertEqual(r.json, {'status': 'bad input'}) self.assertEqual(r.status_code, 400) def test_no_name_post_api_endpoint(self): r = self.app.post('/api', content_type='application/json', data=json.dumps({'age': 100})) self.assertEqual(r.json, {'status': 'bad input'}) self.assertEqual(r.status_code, 400) def test_bad_age_post_api_endpoint(self): r = self.app.post('/api', content_type='application/json', data=json.dumps({'name': 'Den', 'age': '100'})) self.assertEqual(r.json, {'status': 'bad input'}) self.assertEqual(r.status_code, 400) if __name__ == '__main__': unittest.main()
рдХрд╡рд░реЗрдЬ рдЖрдЙрдЯрдкреБрдЯ:
coverage report Name Stmts Miss Cover ------------------------------------------------------------------ src/app.py 28 2 93% src/tests.py 37 0 100% ------------------------------------------------------------------ TOTAL 65 2 96%
рдЕрдм рд╣рдорд╛рд░реА рдкрд╣рд▓реА рдХрд╛рд░реНрд░рд╡рд╛рдИ рдмрдирд╛рдПрдБ, рдЬреЛ рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдПрдЧреАред рдкреНрд░рд▓реЗрдЦрди рдХреЗ рдЕрдиреБрд╕рд╛рд░, рд╕рднреА рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП:
$ mkdir -p .github/workflows $ touch .github/workflows/test_on_push.yaml
рдореИрдВ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХрд┐рд╕реА рднреА рд╢рд╛рдЦрд╛ рдореЗрдВ рдХрд┐рд╕реА рднреА рдкреБрд╢ рдЗрд╡реЗрдВрдЯ рдкрд░ рдЪрд▓реЗ, рд╕рд┐рд╡рд╛рдп рд░рд┐рд▓реАрдЬрд╝ (рдЯреИрдЧ рдХреЗ, рдХреНрдпреЛрдВрдХрд┐ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкрд░реАрдХреНрд╖рдг рд╣реЛрдВрдЧреЗ):
on: push: tags: - '!refs/tags/*' branches: - '*'
рдлрд┐рд░ рд╣рдо рдПрдХ рдРрд╕рд╛ рдХрд╛рд░реНрдп рдмрдирд╛рддреЗ рд╣реИрдВ рдЬреЛ рдЙрдмрдВрдЯреВ рдХреЗ рдирд╡реАрдирддрдо рдЙрдкрд▓рдмреНрдз рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдЪрд▓реЗрдЧрд╛:
jobs: run_tests: runs-on: [ubuntu-latest]
рдЪрд░рдгреЛрдВ рдореЗрдВ, рд╣рдо рдХреЛрдб рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВрдЧреЗ, рдЕрдЬрдЧрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВрдЧреЗ, рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВрдЧреЗ, рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдПрдВрдЧреЗ рдФрд░ рдХрд╡рд░реЗрдЬ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВрдЧреЗ:
steps: # - uses: actions/checkout@master # python - uses: actions/setup-python@v1 with: python-version: '3.8' architecture: 'x64' - name: Install requirements # run: pip install -r requirements.txt - name: Run tests run: coverage run src/tests.py - name: Tests report run: coverage report
рд╕рдм рдПрдХ рд╕рд╛рде name: Run tests on any Push event # push , . # on: push: tags: - '!refs/tags/*' branches: - '*' jobs: run_tests: runs-on: [ubuntu-latest] steps: # - uses: actions/checkout@master # python - uses: actions/setup-python@v1 with: python-version: '3.8' architecture: 'x64' - name: Install requirements # run: pip install -r requirements.txt - name: Run tests run: coverage run src/tests.py - name: Tests report run: coverage report
рдЖрдЗрдП рдХрдорд┐рдЯ рдмрдирд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВ рдФрд░ рджреЗрдЦреЗрдВ рдХрд┐ рд╣рдорд╛рд░реА рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреА рд╣реИред

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

рдПрдХреНрд╢рди рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдЯреЗрд╕реНрдЯ рдХреНрд░реИрд╢
рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдлрд▓ рд░рд╣реЗред рд╕рдВрдХреЗрддрдХ рд▓рд╛рд▓ рд╣реЛ рдЧрдпрд╛ рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдореЗрд▓ рдореЗрдВ рдПрдХ рд╕реВрдЪрдирд╛ рднреА рдорд┐рд▓реАред рдЖрдкрдХреЛ рдХреНрдпрд╛ рдЪрд╛рд╣рд┐рдП! рд▓рдХреНрд╖реНрдп рдпреЛрдЬрдирд╛ рдХреЗ 8 рдореЗрдВ рд╕реЗ 3 рдмрд┐рдВрджреБрдУрдВ рдХреЛ рдкреВрд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЕрдм рд╣рдорд╛рд░реЗ рдбреЙрдХрдЯрд░ рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд╕рдВрдпреЛрдЬрди, рднрдВрдбрд╛рд░рдг рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред
рдиреЛрдЯ! рдЖрдЧреЗ рд╣рдореЗрдВ рдПрдХ рдбреЙрдХрдЯрд░ рдЦрд╛рддреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдПрдХ рд╕рд░рд▓ рдбреЙрдХрд░рдлрд╛рдЗрд▓ рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬрд┐рд╕рдореЗрдВ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
Dockerfile # FROM python:3.8-alpine # /app COPY ./ /app # RUN apk update && pip install -r /app/requirements.txt --no-cache-dir # ( Distutils) RUN pip install -e /app # EXPOSE 8080 # CMD web_server # distutils #CMD python /app/src/app.py
рдХрдВрдЯреЗрдирд░ рдХреЛ рд╣рдм рдкрд░ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП, рдбреЙрдХрдЯрд░ рдХреЛ рд▓реЙрдЧ рдЗрди рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛, рд▓реЗрдХрд┐рди рдЬрдм рд╕реЗ рдореИрдВ рдкреВрд░реА рджреБрдирд┐рдпрд╛ рдХреЛ рдЦрд╛рддреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рд╕рд╡рд░реНрдб рдирд╣реАрдВ рд╕реАрдЦрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдореИрдВ рдЧрд┐рдЯрд╣рдм рдореЗрдВ рдирд┐рд░реНрдорд┐рдд рд░рд╣рд╕реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛ред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдХреЗрд╡рд▓ рдкрд╛рд╕рд╡рд░реНрдб рдХреЛ рд░рд╣рд╕реНрдпреЛрдВ рдореЗрдВ рдбрд╛рд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдмрд╛рдХреА рдХреЛ * .yaml рдореЗрдВ рд╣рд╛рд░реНрдбрдХреЛрдб рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдпрд╣ рдХрд╛рдо рдХрд░реЗрдЧрд╛ред рд▓реЗрдХрд┐рди рдореИрдВ рдмрджрд▓рд╛рд╡ рдХреЗ рдмрд┐рдирд╛ рдЕрдкрдиреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХреЙрдкреА-рдкреЗрд╕реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдФрд░ рд░рд╣рд╕реНрдпреЛрдВ рд╕реЗ рд╕рднреА рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЬрд╛рдирдХрд╛рд░реА рдЦреАрдВрдЪрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

рдЬреАрдердм рд░рд╛рдЬ
DOCKER_LOGIN - hub.docker.com рдореЗрдВ рд▓реЙрдЧрд┐рди рдХрд░реЗрдВ
DOCKER_PWD - рдкрд╛рд╕рд╡рд░реНрдб
DOCKER_NAME - рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП docker рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХрд╛ рдирд╛рдо (рдЕрдЧреНрд░рд┐рдо рдореЗрдВ рдмрдирд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП)
рдареАрдХ рд╣реИ, рддреИрдпрд╛рд░реА рд╣реЛ рдЧрдИ рд╣реИ, рдЕрдм рдЕрдкрдиреА рджреВрд╕рд░реА рдХрд╛рд░реНрд░рд╡рд╛рдИ рдмрдирд╛рддреЗ рд╣реИрдВ:
$ touch .github/workflows/pub_on_release.yaml
рд╣рдо рд▓реЙрдиреНрдЪ рдЯреНрд░рд┐рдЧрд░ рдХреЗ рдЕрдкрд╡рд╛рдж рдХреЗ рд╕рд╛рде рдкрд┐рдЫрд▓реА рдХрд╛рд░реНрд░рд╡рд╛рдИ рд╕реЗ рдкрд░реАрдХреНрд╖рдг рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдмрдирд╛рддреЗ рд╣реИрдВ (рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдерд╛ рдХрд┐ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХреИрд╕реЗ рдЖрдпрд╛рдд рдХрд┐рдпрд╛ рдЬрд╛рдП)ред рд╣рдо рдЗрд╕реЗ "рд▓реЙрдиреНрдЪ рдкрд░ рд▓реЙрдиреНрдЪ" рд╕реЗ рдмрджрд▓рддреЗ рд╣реИрдВ:
on: release: types: [published]
рдорд╣рддреНрд╡рдкреВрд░реНрдг! рдпрд╣ рд╕рд╣реА рд╕реНрдерд┐рддрд┐ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ on.release рдкреНрд░рдХрд╛рд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдШрдЯрдирд╛ рдХрдо рд╕реЗ рдХрдо 2 рдШрдЯрдирд╛рдУрдВ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рддреА рд╣реИ: рдкреНрд░рдХрд╛рд╢рд┐рдд рдФрд░ рдмрдирд╛рдИ рдЧрдИред рдпрд╛рдиреА 2 рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдПрдВ рддреБрд░рдВрдд рд╢реБрд░реВ рдХреА рдЬрд╛рдПрдВрдЧреАред
рдЕрдм рдЙрд╕реА рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╣рдо рдкрд╣рд▓реЗ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рдФрд░ рдХрд╛рд░реНрдп рдХрд░реЗрдВрдЧреЗ:
build_and_pub: needs: [run_tests]
рдЬрд░реВрд░рддреЛрдВ - рдХрд╛ рдХрд╣рдирд╛ рд╣реИ рдХрд┐ рдпрд╣ рдХрд╛рд░реНрдп рддрдм рддрдХ рд╢реБрд░реВ рдирд╣реАрдВ рд╣реЛрдЧрд╛ рдЬрдм рддрдХ run_tests рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рд╣реЛрддреА
рдорд╣рддреНрд╡рдкреВрд░реНрдг! рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдХрдИ рдПрдХреНрд╢рди рдлрд╛рдЗрд▓реЗрдВ рд╣реИрдВ, рдФрд░ рдЙрдирдХреЗ рднреАрддрд░ рдХрдИ рдХрд╛рд░реНрдп рд╣реИрдВ, рддреЛ рд╡реЗ рд╕рднреА рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рдПрдХ рд╕рд╛рде рдЪрд▓рддреЗ рд╣реИрдВред рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рд╡рд╛рддрд╛рд╡рд░рдг рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЕрдиреНрдп рдХрд╛рд░реНрдпреЛрдВ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ред рдпрджрд┐ рдЖрдк рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдкрд░реАрдХреНрд╖рдг рдХрд╛рд░реНрдп рдФрд░ рд╡рд┐рдзрд╛рдирд╕рднрд╛рдУрдВ рдХреЛ рдПрдХ рд╕рд╛рде рдФрд░ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рдЬреЛрдбрд╝реЗрдВ рдЬрд┐рд╕рдореЗрдВ рд╣рдорд╛рд░реЗ рд░рд╣рд╕реНрдп рд╣реЛрдВрдЧреЗ:
env: LOGIN: ${{ secrets.DOCKER_LOGIN }} NAME: ${{ secrets.DOCKER_NAME }}
рдЕрдм рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдп рдХреЗ рдЪрд░рдг, рдЙрдирдореЗрдВ рд╣рдореЗрдВ рдбреЙрдХрдЯрд░ рдореЗрдВ рд▓реЙрдЧ рдЗрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдХрдВрдЯреЗрдирд░ рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдЗрд╕реЗ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдореЗрдВ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛:
steps: - name: Login to docker.io run: echo ${{ secrets.DOCKER_PWD }} | docker login -u ${{ secrets.DOCKER_LOGIN }} --password-stdin - uses: actions/checkout@master - name: Build image run: docker build -t $LOGIN/$NAME:${GITHUB_REF:11} -f Dockerfile . - name: Push image to docker.io run: docker push $LOGIN/$NAME:${GITHUB_REF:11}
$ {GITHUB_REF: 11} рдПрдХ github рд╡реИрд░рд┐рдПрдмрд▓ рд╣реИ рдЬреЛ рдЙрд╕ рдШрдЯрдирд╛ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдПрдХ рдкрдВрдХреНрддрд┐ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдЯреНрд░рд┐рдЧрд░ рдиреЗ рдХрд╛рдо рдХрд┐рдпрд╛ рд╣реИ (рд╢рд╛рдЦрд╛ рдХрд╛ рдирд╛рдо, рдЯреИрдЧ, рдЖрджрд┐), рдЕрдЧрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ "v0.0.0" рдкреНрд░рд╛рд░реВрдк рдХрд╛ рдЯреИрдЧ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдкрд╣рд▓реЗ 11 рдХреЛ рдЯреНрд░рд┐рдо рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рд╡рд░реНрдг, рдлрд┐рд░ "0.0.0" рд░рд╣рддрд╛ рд╣реИред
рдХреЛрдб рдХреЛ рдкреБрд╢ рдХрд░реЗрдВ рдФрд░ рдПрдХ рдирдпрд╛ рдЯреИрдЧ рдмрдирд╛рдПрдВред рдФрд░ рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдХрдВрдЯреЗрдирд░ рдХреЛ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рдФрд░ рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдХреЛ рднреЗрдЬрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рд╣рдордиреЗ рдХрд╣реАрдВ рднреА рдЕрдкрдирд╛ рдкрд╛рд╕рд╡рд░реНрдб рдирд╣реАрдВ рджрд┐рдЦрд╛рдпрд╛ред

рдПрдХреНрд╢рди рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдмрд┐рд▓реНрдб рдФрд░ рд╢рд┐рдк рдХрдВрдЯреЗрдирд░
рд╣рдм рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ:

рдХрдВрдЯреЗрдирд░ рдбреВрдХрд░ рд╣рдм рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд
рд╕рдм рдХреБрдЫ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдмрд╕реЗ рдореБрд╢реНрдХрд┐рд▓ рдХрд╛рдо рд░рд╣рддрд╛ рд╣реИ - рддреИрдирд╛рддреАред рдпрд╣рд╛рдВ рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рд╡реАрдкреАрдПрд╕ рдФрд░ рдПрдХ рд╕рдлреЗрдж рдЖрдИрдкреА рдкрддреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА рдЬрд╣рд╛рдВ рд╣рдо рдХрдВрдЯреЗрдирд░ рдХреЛ рддреИрдирд╛рдд рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЬрд╣рд╛рдВ рдЖрдк рд╣реБрдХ рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВред рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рд╡реАрдкреАрдПрд╕ рдпрд╛ рд╣реЛрдо рд╕рд░реНрд╡рд░ рдХреЗ рдХрд┐рдирд╛рд░реЗ, рдЖрдк рддрд╛рдЬ рдкрд░ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЪрд▓рд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдПрдХ рдирдИ рдЫрд╡рд┐ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдЗрд╕реЗ рдЖрдЧ рджреЗрдЧрд╛, рдпрд╛ рдХрд┐рд╕реА рддрд░рд╣ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо рдмреЙрдЯ рдХреЗ рд╕рд╛рде рдЦреЗрд▓реЗрдВрдЧреЗред рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рдХрдИ рддрд░реАрдХреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдореИрдВ рдмрд╛рд╣рд░реА рдЖрдИрдкреА рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░реВрдВрдЧрд╛ред рд╕реНрдорд╛рд░реНрдЯ рдирд╣реАрдВ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдлреНрд▓рд╛рд╕реНрдХ рдореЗрдВ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдПрдкреАрдЖрдИ рдХреЗ рд╕рд╛рде рдПрдХ рдЫреЛрдЯреА рд╡реЗрдм рд╕реЗрд╡рд╛ рд▓рд┐рдЦреАред
рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, 1 рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ "/" рд╣реИред
рдПрдХ GET рдЕрдиреБрд░реЛрдз рдореЗрдЬрдмрд╛рди рдкрд░ рд╕рднреА рд╕рдХреНрд░рд┐рдп рдХрдВрдЯреЗрдирд░реЛрдВ рдХреЗ рд╕рд╛рде рдЬреМрди рджреЗрддрд╛ рд╣реИред
POST - рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ:
{ "owner": " ", "repository": " ", "tag": "v0.0.1", # "ports": {"8080": 8080, тАЬ443тАЭ: 443} # }
рдореЗрдЬрдмрд╛рди рдкрд░ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ:
- рдкреНрд░рд╛рдкреНрдд json рд╕реЗ рдПрдХ рдирдИ рдЫрд╡рд┐ рдХрд╛ рдирд╛рдо
- рдПрдХ рдирдИ рдЫрд╡рд┐ рдЙрднрдбрд╝рд╛ рд╣реБрдЖ рд╣реИ
- рдпрджрд┐ рдЪрд┐рддреНрд░ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рд╡рд░реНрддрдорд╛рди рдХрдВрдЯреЗрдирд░ рдХреЛ рд░реЛрдХ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
- рдмрдВрджрд░рдЧрд╛рд╣реЛрдВ рдХреЗ рдкреНрд░рдХрд╛рд╢рди (-p рдзреНрд╡рдЬ) рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ рдХрдВрдЯреЗрдирд░ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ
Docker рдХреЗ рд╕рд╛рде рд╕рднреА рдХрд╛рд░реНрдп docker-py рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдЗрд╕ рддрд░рд╣ рдХреА рд╕реЗрд╡рд╛ рдХреЛ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдиреНрдпреВрдирддрдо рд╕реБрд░рдХреНрд╖рд╛ рдХреЗ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рдирд╛ рдмрд╣реБрдд рдЧрд▓рдд рд╣реЛрдЧрд╛, рдФрд░ рдореИрдВрдиреЗ рдПрдкреАрдЖрдИ рдХреБрдВрдЬреА рдХрд╛ рдПрдХ рд╕рд╛рджреГрд╢реНрдп рдмрдирд╛рдпрд╛, рд╕реЗрд╡рд╛ рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рд╕реЗ рдЯреЛрдХрди рдкрдврд╝рддреА рд╣реИ, рдФрд░ рдлрд┐рд░ рд╣реЗрдбрд░ рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░рддреА рд╣реИ {рдкреНрд░рд╛рдзрд┐рдХрд░рдг: CI_RKEN}
рддреИрдирд╛рддреА рдХреЗ рд▓рд┐рдП рд╡реЗрдм рд╕рд░реНрд╡рд░ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЗрд╕реЗ рд╕рд┐рд╕реНрдЯрдо рдкрд░ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП setup.py рднреА рдХрд┐рдпрд╛ред рдЖрдк рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрдерд╛рдкрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
$ python3 setup.sy install
рдмрд╢рд░реНрддреЗ рдХрд┐ рдЖрдкрдиреЗ рдлрд╝рд╛рдЗрд▓реЗрдВ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░ рд▓реА рд╣реИрдВ рдФрд░ рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рд╣реИрдВред
рд╕реНрдерд╛рдкрдирд╛ рдХреЗ рдмрд╛рдж, рдЖрдкрдХреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдПрдХ рд╕реЗрд╡рд╛ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдХреНрд╖рдо рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рддрд╛рдХрд┐ рдпрд╣ рд╕рд░реНрд╡рд░ рд░рд┐рдмреВрдЯ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╕реНрд╡рдпрдВ рд╢реБрд░реВ рд╣реЛ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд╕рд┐рд╕реНрдЯрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ
рдпрд╣рд╛рдБ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╡рд┐рдиреНрдпрд╛рд╕ рдлрд╛рдЗрд▓ рд╣реИ:
[Unit] Description=Deployment web server After=network-online.target [Service] Type=simple RestartSec=3 ExecStart=/usr/local/bin/ci_example Environment=CI_TOKEN=#<I generate it with $(openssl rand -hex 20)> [Install] WantedBy=multi-user.target
рдпрд╣ рдХреЗрд╡рд▓ рдЗрд╕реЗ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ:
$ sudo systemctl daemon-reload $ sudo systemctl enable ci_example.service $ sudo systemctl start ci_example.service
рдЖрдк рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡реЗрдм рдбрд┐рд▓реАрд╡рд░реА рд╕рд░реНрд╡рд░ рдХрд╛ рд▓реЙрдЧ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ
$ sudo systemctl status ci_example.service
рд╕рд░реНрд╡рд░ рднрд╛рдЧ рддреИрдпрд╛рд░ рд╣реИ, рдпрд╣ рдХреЗрд╡рд▓ рд╣рдорд╛рд░реА рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реБрдХ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╣реБрдЖ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рд╕рд░реНрд╡рд░ рдХреЗ рдЖрдИрдкреА рдкрддреЗ рдФрд░ CI_TOKEN рдХреЗ рд░рд╣рд╕реНрдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝реЗрдВ рдЬреЛ рд╣рдордиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рддреЗ рд╕рдордп рдЙрддреНрдкрдиреНрди рдХрд┐рдП рдереЗред
рдкрд╣рд▓реЗ рддреЛ рдореИрдВ рдЬреАрдердм рдорд╛рд░реНрдХреЗрдЯрдкреНрд▓реЗрд╕ рд╕реЗ рдХрд░реНрд▓ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдХрд┐рдП рдЧрдП рдПрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛, рд▓реЗрдХрд┐рди рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдпрд╣ POST рдЕрдиреБрд░реЛрдз рдХреЗ рд╢рд░реАрд░ рд╕реЗ рдЙрджреНрдзрд░рдгреЛрдВ рдХреЛ рд╣рдЯрд╛ рджреЗрддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ json рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реЛ рдЧрдпрд╛ред рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдореЗрд░реЗ рдЕрдиреБрдХреВрд▓ рдирд╣реАрдВ рдерд╛, рдФрд░ рдореИрдВрдиреЗ рдЙрдмрдВрдЯреВ рдореЗрдВ рдирд┐рд░реНрдорд┐рдд рдХрд░реНрд▓ (рдЬрд┐рд╕ рдкрд░ рдореИрдВ рдХрдВрдЯреЗрдирд░ рдЗрдХрдЯреНрдард╛ рдХрд░рддрд╛ рд╣реИ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдЬреЛ рд╕рдВрдпреЛрдЧрд╡рд╢ рдкреНрд░рджрд░реНрд╢рди рдкрд░ рд╕рдХрд╛рд░рд╛рддреНрдордХ рдкреНрд░рднрд╛рд╡ рдбрд╛рд▓рддрд╛ рдерд╛, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЕрддрд┐рд░рд┐рдХреНрдд рдХрдВрдЯреЗрдирд░ рдХреЗ рд╕рдВрдпреЛрдЬрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ:
deploy: needs: [build_and_pub] runs-on: [ubuntu-latest] steps: - name: Set tag to env run: echo ::set-env name=TAG::$(echo ${GITHUB_REF:11}) - name: Send webhook for deploy run: "curl --silent --show-error --fail -X POST ${{ secrets.DEPLOYMENT_SERVER }} -H 'Authorization: ${{ secrets.DEPLOYMENT_TOKEN }}' -H 'Content-Type: application/json' -d '{\"owner\": \"${{ secrets.DOCKER_LOGIN }}\", \"repository\": \"${{ secrets.DOCKER_NAME }}\", \"tag\": \"${{ env.TAG }}\", \"ports\": {\"8080\": 8080}}'"
рдиреЛрдЯ: - рд╕реНрд╡рд┐рдЪ рд╕реНрд╡рд┐рдЪ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рдмрд╣реБрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ, рдЕрдиреНрдпрдерд╛ рдХреЛрдИ рднреА рдЕрдиреБрд░реЛрдз рд╕рдлрд▓ рд╣реЛрдЧрд╛, рднрд▓реЗ рд╣реА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдкреНрд░рд╛рдкреНрдд рд╣реБрдИ рд╣реЛред
рдпрд╣ рднреА рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдЪрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЪрд░ рдирд╣реАрдВ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╡рд┐рд╢реЗрд╖ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ GITHUB_REF рдХреЗ рдЕрдкрд╡рд╛рдж рдХреЗ рд╕рд╛рде рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдореБрдЭреЗ рд╕рдордЭ рдирд╣реАрдВ рдЖрдпрд╛ рдХрд┐ рдЕрдиреБрд░реЛрдз рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдХрд╛рдо рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рдерд╛ред рд▓реЗрдХрд┐рди рдЗрд╕рд╕реЗ рдПрдХ рдлрдВрдХреНрд╢рди рдмрдирд╛, рд╕рдм рдХреБрдЫ рдХрд╛рдо рдХрд░ рдЧрдпрд╛ред
рдХрд╛рд░реНрд░рд╡рд╛рдИ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рддреИрдирд╛рдд рдХрд░рддрд╛ рд╣реИ name: Publish on Docker Hub and Deploy on: release: types: [published] # jobs: run_tests: # runs-on: [ubuntu-latest] steps: # - uses: actions/checkout@master # python - uses: actions/setup-python@v1 with: python-version: '3.8' architecture: 'x64' - name: Install requirements # run: pip install -r requirements.txt - name: Run tests # run: coverage run src/tests.py - name: Tests report run: coverage report build_and_pub: # needs: [run_tests] runs-on: [ubuntu-latest] env: LOGIN: ${{ secrets.DOCKER_LOGIN }} NAME: ${{ secrets.DOCKER_NAME }} steps: - name: Login to docker.io # docker.io run: echo ${{ secrets.DOCKER_PWD }} | docker login -u ${{ secrets.DOCKER_LOGIN }} --password-stdin # - uses: actions/checkout@master - name: Build image # image hub.docker .. login/repository:version run: docker build -t $LOGIN/$NAME:${GITHUB_REF:11} -f Dockerfile . - name: Push image to docker.io # registry run: docker push $LOGIN/$NAME:${GITHUB_REF:11} deploy: # registry, # curl needs: [build_and_pub] runs-on: [ubuntu-latest] steps: - name: Set tag to env run: echo ::set-env name=RELEASE_VERSION::$(echo ${GITHUB_REF:11}) - name: Send webhook for deploy run: "curl --silent --show-error --fail -X POST ${{ secrets.DEPLOYMENT_SERVER }} -H 'Authorization: ${{ secrets.DEPLOYMENT_TOKEN }}' -H 'Content-Type: application/json' -d '{\"owner\": \"${{ secrets.DOCKER_LOGIN }}\", \"repository\": \"${{ secrets.DOCKER_NAME }}\", \"tag\": \"${{ env.RELEASE_VERSION }}\", \"ports\": {\"8080\": 8080}}'"
рдареАрдХ рд╣реИ, рд╣рдордиреЗ рдЗрд╕реЗ рдПрдХ рд╕рд╛рде рд░рдЦрд╛ рд╣реИ, рдЕрдм рд╣рдо рдПрдХ рдирдИ рд░рд┐рд▓реАрдЬрд╝ рдмрдирд╛рдПрдВрдЧреЗ рдФрд░ рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рджреЗрдЦреЗрдВрдЧреЗред

рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрд░рд┐рдирд┐рдпреЛрдЬрди рдХреЗ рд▓рд┐рдП Webhook
рд╕рдм рдХреБрдЫ рдмрджрд▓ рдЧрдпрд╛, рд╣рдо рддреИрдирд╛рддреА рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП рдПрдХ GET рдЕрдиреБрд░реЛрдз рдХрд░рддреЗ рд╣реИрдВ (рдореЗрдЬрдмрд╛рди рдкрд░ рд╕рднреА рд╕рдХреНрд░рд┐рдп рдХрдВрдЯреЗрдирд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ):

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

рддреИрдирд╛рдд рдХрдВрдЯреЗрдирд░ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ

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