{"id":75696,"date":"2024-09-04T16:00:06","date_gmt":"2024-09-04T12:30:06","guid":{"rendered":"https:\/\/nabfollower.com\/blog\/from-legacy-to-cloud-serverless-part-3-4abm\/"},"modified":"2024-09-04T16:00:06","modified_gmt":"2024-09-04T12:30:06","slug":"from-legacy-to-cloud-serverless-part-3-4abm","status":"publish","type":"post","link":"https:\/\/nabfollower.com\/blog\/from-legacy-to-cloud-serverless-part-3-4abm\/","title":{"rendered":"\u0627\u0632 \u0645\u06cc\u0631\u0627\u062b \u062a\u0627 \u0628\u062f\u0648\u0646 \u0633\u0631\u0648\u0631 \u0627\u0628\u0631\u06cc &#8211; \u0642\u0633\u0645\u062a 3"},"content":{"rendered":"<p>Summarize this content to 400 words in Persian Lang<br \/>\n\u062a\u0648\u062c\u0647: \u0627\u06cc\u0646 \u0645\u0642\u0627\u0644\u0647 \u062f\u0631 \u0627\u0628\u062a\u062f\u0627 \u062f\u0631 \u062a\u0627\u0631\u06cc\u062e \u0645\u0646\u062a\u0634\u0631 \u0634\u062f\u0647 \u0627\u0633\u062a<br \/>\n25 \u062f\u0633\u0627\u0645\u0628\u0631 2023 \u0627\u06cc\u0646\u062c\u0627. \u0628\u0631\u0627\u06cc \u062f\u0633\u062a\u06cc\u0627\u0628\u06cc \u0628\u0647 \u0645\u062e\u0627\u0637\u0628\u0627\u0646 \u0628\u06cc\u0634\u062a\u0631 \u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u0628\u0627\u0632\u0646\u0634\u0631 \u0634\u062f\u0647 \u0627\u0633\u062a.<\/p>\n<p>\u0628\u0647 \u0642\u0633\u0645\u062a \u0633\u0648\u0645 \u0627\u06cc\u0646 \u0633\u0631\u06cc\u0627\u0644 \u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f! \u062f\u0631 \u0627\u06cc\u0646 \u0628\u062e\u0634\u060c \u0628\u0647 \u0622\u0632\u0645\u0627\u06cc\u0634\u200c\u0647\u0627 \u0648 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u062e\u0637 \u0644\u0648\u0644\u0647 \u062f\u0631 Google Cloud \u0645\u06cc\u200c\u067e\u0631\u062f\u0627\u0632\u06cc\u0645\u060c \u0628\u0647\u200c\u0648\u06cc\u0698\u0647 \u0628\u0631 \u0631\u0648\u06cc \u06cc\u06a9\u067e\u0627\u0631\u0686\u0647\u200c\u0633\u0627\u0632\u06cc \u0645\u062f\u0627\u0648\u0645 \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 Cloud Build\u060c \u0627\u0633\u06a9\u0646\u0631 \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc \u0648 \u062b\u0628\u062a \u0645\u0635\u0646\u0648\u0639 \u062a\u0645\u0631\u06a9\u0632 \u0645\u06cc\u200c\u06a9\u0646\u06cc\u0645. \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u0645\u062e\u0632\u0646 \u067e\u0631\u0648\u0698\u0647 \u0631\u0627 \u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u067e\u06cc\u062f\u0627 \u06a9\u0646\u06cc\u062f\u060c \u06cc\u0627 \u062f\u0631 \u0635\u0648\u0631\u062a \u062a\u0645\u0627\u06cc\u0644\u060c \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u067e\u0631\u0648\u0698\u0647 \u062e\u0648\u062f \u0631\u0627 \u0628\u06cc\u0627\u0648\u0631\u06cc\u062f.<\/p>\n<p>\u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f \u0634\u0645\u0627 \u0631\u0627 \u0627\u0632 \u0637\u0631\u06cc\u0642 \u062e\u0637 \u0644\u0648\u0644\u0647 \u0631\u0627\u0647\u0646\u0645\u0627\u06cc\u06cc \u06a9\u0646\u0645. \u0628\u0627 \u0647\u0631 \u0641\u0634\u0627\u0631 \u062f\u0627\u062f\u0646 \u0628\u0647 \u0634\u0627\u062e\u0647 \u0627\u0635\u0644\u06cc\u060c Cloud Build \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc \u0645\u06cc \u0634\u0648\u062f. \u0627\u0628\u062a\u062f\u0627 \u062a\u0633\u062a \u0647\u0627\u06cc \u0648\u0627\u062d\u062f \u0631\u0627 \u0631\u0648\u06cc \u06a9\u062f \u0627\u062c\u0631\u0627 \u0645\u06cc \u06a9\u0646\u062f. \u062f\u0631 \u0635\u0648\u0631\u062a \u0645\u0648\u0641\u0642\u06cc\u062a \u0622\u0645\u06cc\u0632 \u0628\u0648\u062f\u0646 \u062a\u0633\u062a \u0647\u0627\u060c \u0627\u0642\u062f\u0627\u0645 \u0628\u0647 \u0633\u0627\u062e\u062a \u062a\u0635\u0648\u06cc\u0631 \u0645\u06cc \u06a9\u0646\u062f. \u067e\u0633 \u0627\u0632 \u0633\u0627\u062e\u062a\u0647 \u0634\u062f\u0646 \u062a\u0635\u0648\u06cc\u0631\u060c Cloud Build \u0627\u0633\u06a9\u0646\u0631 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0641\u0631\u0627\u062e\u0648\u0627\u0646\u06cc \u0645\u06cc \u06a9\u0646\u062f \u062a\u0627 \u0627\u0632 \u0639\u0627\u0631\u06cc \u0628\u0648\u062f\u0646 \u0622\u0646 \u0627\u0632 \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u0627\u0637\u0645\u06cc\u0646\u0627\u0646 \u062d\u0627\u0635\u0644 \u06a9\u0646\u062f. \u0627\u06af\u0631 \u0647\u0645\u0647 \u0686\u06cc\u0632 \u062e\u0648\u0628 \u0628\u0627\u0634\u062f\u060c \u062a\u0635\u0648\u06cc\u0631 \u0627\u0631\u0633\u0627\u0644 \u0634\u062f\u0647 \u0648 \u062f\u0631 \u0622\u0631\u062a\u06cc\u0641\u06a9\u062a \u0631\u062c\u06cc\u0633\u062a\u0631\u06cc \u0630\u062e\u06cc\u0631\u0647 \u0645\u06cc \u0634\u0648\u062f \u0648 \u0622\u0645\u0627\u062f\u0647 \u0627\u0633\u062a\u0642\u0631\u0627\u0631 \u0627\u0633\u062a. \u0627\u0645\u0627 \u0628\u0631\u0627\u06cc \u0627\u06cc\u0646 \u0645\u0642\u0627\u0644\u0647\u060c \u0645\u0627 \u0641\u0642\u0637 \u0628\u0631 \u0631\u0648\u06cc \u0628\u062e\u0634 CI \u062a\u0645\u0631\u06a9\u0632 \u062e\u0648\u0627\u0647\u06cc\u0645 \u06a9\u0631\u062f. \u0628\u06cc\u0627\u06cc\u06cc\u062f \u0628\u0627 \u0622\u0632\u0645\u0627\u06cc\u0634\u0627\u062a \u0634\u0631\u0648\u0639 \u06a9\u0646\u06cc\u0645.<\/p>\n<p>  \u0648\u0627\u062d\u062f \u062a\u0633\u062a<\/p>\n<p>\u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u06a9\u062f\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0642\u0635\u062f \u0622\u0632\u0645\u0627\u06cc\u0634 \u0622\u0646 \u0631\u0627 \u062f\u0627\u0631\u06cc\u0645<\/p>\n<p>import os<br \/>\nfrom flask import Flask<br \/>\nfrom pymongo import MongoClient<br \/>\nfrom flask import Flask, render_template, request, url_for, redirect<br \/>\nfrom bson.objectid import ObjectId<br \/>\nimport mongomock<\/p>\n<p>app = Flask(__name__, template_folder=&#8217;templates&#8217;)<\/p>\n<p>if os.environ.get(&#8216;TESTING&#8217;):<br \/>\n    client = mongomock.MongoClient()<br \/>\nelse:<br \/>\n    client = MongoClient(os.environ[&#8216;MONGO_URI&#8217;])<\/p>\n<p>db = client.flask_db<br \/>\ntodos = db.todos<\/p>\n<p>@app.route(&#8216;\/&#8217;, methods=(&#8216;GET&#8217;, &#8216;POST&#8217;))<br \/>\ndef index():<br \/>\n    if request.method==&#8217;POST&#8217;:<br \/>\n        content = request.form[&#8216;content&#8217;]\n        degree = request.form[&#8216;degree&#8217;]\n        todos.insert_one({&#8216;content&#8217;: content, &#8216;degree&#8217;: degree})<br \/>\n        return redirect(url_for(&#8216;index&#8217;))<\/p>\n<p>    all_todos = todos.find()<br \/>\n    return render_template(&#8216;index.html&#8217;, todos=all_todos)<\/p>\n<p>@app.post(&#8216;\/&lt;id&gt;\/delete\/&#8217;)<br \/>\ndef delete(id):<br \/>\n    todos.delete_one({&#8220;_id&#8221;: ObjectId(id)})<br \/>\n    return redirect(url_for(&#8216;index&#8217;))<\/p>\n<p>\u0628\u0631\u0627\u06cc \u062a\u0648\u0636\u06cc\u062d \u06a9\u062f \u0628\u0647 \u0645\u0642\u0627\u0644\u0647 \u0627\u0648\u0644 \u0627\u06cc\u0646 \u0645\u062c\u0645\u0648\u0639\u0647 \u0645\u0631\u0627\u062c\u0639\u0647 \u06a9\u0646\u06cc\u062f.<\/p>\n<p>\u062d\u0627\u0644\u0627 \u0628\u06cc\u0627\u06cc\u06cc\u062f \u0628\u0647 \u0645\u0631\u062d\u0644\u0647 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0628\u0631\u0648\u06cc\u0645<\/p>\n<p>\u0627\u06cc\u0646 \u062a\u0633\u062a \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 \u062f\u0627\u062e\u0644\u06cc \u067e\u0627\u06cc\u062a\u0648\u0646 \u0646\u0648\u0634\u062a\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a unittest \u0645\u0627\u0698\u0648\u0644\u060c \u06a9\u0647 \u0686\u0627\u0631\u0686\u0648\u0628\u06cc \u0628\u0631\u0627\u06cc \u0646\u0648\u0634\u062a\u0646 \u0648 \u0627\u062c\u0631\u0627\u06cc \u062a\u0633\u062a \u0647\u0627 \u0641\u0631\u0627\u0647\u0645 \u0645\u06cc \u06a9\u0646\u062f.<\/p>\n<p>\u0645\u0627\u0698\u0648\u0644 \u0647\u0627\u06cc \u0644\u0627\u0632\u0645 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f \u0648 \u06cc\u06a9 \u0646\u0645\u0648\u0646\u0647 \u0633\u0627\u062e\u062a\u06af\u06cc MongoDB \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f<\/p>\n<p>\u062a\u0633\u062a \u0628\u0627 \u0648\u0627\u0631\u062f \u06a9\u0631\u062f\u0646 \u0645\u0627\u0698\u0648\u0644 \u0647\u0627\u06cc \u0644\u0627\u0632\u0645 \u0622\u063a\u0627\u0632 \u0645\u06cc \u0634\u0648\u062f. unittest \u0686\u0627\u0631\u0686\u0648\u0628 \u062a\u0633\u062a \u0627\u0633\u062a\u060c patch \u0648 MagicMock \u0627\u0632 unittest.mock \u0628\u0631\u0627\u06cc \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc \u0628\u062e\u0634 \u0647\u0627\u06cc\u06cc \u0627\u0632 \u0633\u06cc\u0633\u062a\u0645 \u06a9\u0647 \u062f\u0631 \u062d\u0627\u0644 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0622\u0646\u0647\u0627 \u0647\u0633\u062a\u06cc\u062f \u0628\u0627 \u0627\u0634\u06cc\u0627\u0621 \u0633\u0627\u062e\u062a\u06af\u06cc \u0648 ObjectId \u0627\u0632 bson.objectid \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u0634\u0646\u0627\u0633\u0647 \u0647\u0627\u06cc \u0645\u0646\u062d\u0635\u0631 \u0628\u0647 \u0641\u0631\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 app \u0648 todos \u0627\u0632 \u06a9\u0634\u0648\u0631 \u0648\u0627\u0631\u062f \u0645\u06cc \u0634\u0648\u0646\u062f app.py \u0641\u0627\u06cc\u0644 mongomock \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u0646\u0645\u0648\u0646\u0647 MongoDB \u0633\u0627\u062e\u062a\u06af\u06cc \u0628\u0631\u0627\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f \u0648 flask \u0628\u0631\u0627\u06cc \u062f\u0633\u062a\u06a9\u0627\u0631\u06cc \u0632\u0645\u06cc\u0646\u0647 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u062f\u0631 \u0637\u0648\u0644 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f.<\/p>\n<p>import unittest<br \/>\nfrom unittest.mock import patch, MagicMock<br \/>\nfrom bson.objectid import ObjectId<br \/>\nfrom app import app, todos<br \/>\nimport mongomock<br \/>\nimport flask<\/p>\n<p>mock_db = mongomock.MongoClient().db<\/p>\n<p>\u0645\u0648\u0631\u062f \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0631\u0627 \u062a\u0639\u0631\u06cc\u0641 \u06a9\u0646\u06cc\u062f<\/p>\n<p>\u06cc\u06a9 \u0645\u0648\u0631\u062f \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0628\u0627 \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u06a9\u0644\u0627\u0633 \u062c\u062f\u06cc\u062f \u06a9\u0647 \u0627\u0632 \u0622\u0646 \u0627\u0631\u062b \u0645\u06cc \u0628\u0631\u062f\u060c \u062a\u0639\u0631\u06cc\u0641 \u0645\u06cc \u0634\u0648\u062f unittest.TestCase. \u0627\u06cc\u0646 \u06a9\u0644\u0627\u0633 \u062d\u0627\u0648\u06cc \u0645\u062a\u062f\u0647\u0627\u06cc\u06cc \u062e\u0648\u0627\u0647\u062f \u0628\u0648\u062f \u06a9\u0647 \u062a\u0633\u062a \u0647\u0627\u06cc \u0641\u0631\u062f\u06cc \u0631\u0627 \u0646\u0634\u0627\u0646 \u0645\u06cc \u062f\u0647\u0646\u062f.<\/p>\n<p>class\u00a0TestApp(unittest.TestCase):<\/p>\n<p>\u0645\u062d\u06cc\u0637 \u062a\u0633\u062a \u0631\u0627 \u062a\u0646\u0638\u06cc\u0645 \u06a9\u0646\u06cc\u062f<\/p>\n<p>\u0627\u06cc\u0646 setUp \u0645\u062a\u062f \u0631\u0648\u0634 \u062e\u0627\u0635\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0642\u0628\u0644 \u0627\u0632 \u0647\u0631 \u062a\u0633\u062a \u0627\u062c\u0631\u0627 \u0645\u06cc \u0634\u0648\u062f. \u062f\u0631 \u0627\u06cc\u0646\u062c\u0627\u060c \u0627\u0632 \u0622\u0646 \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u0646\u0645\u0648\u0646\u0647 \u0645\u0634\u062a\u0631\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0627\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 Flask \u0648 \u0641\u0639\u0627\u0644 \u06a9\u0631\u062f\u0646 \u062d\u0627\u0644\u062a \u062a\u0633\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f.<\/p>\n<p>def setUp(self):<br \/>\n    self.app = app.test_client()<br \/>\n    self.app.testing = True<\/p>\n<p>\u062a\u0633\u062a \u0631\u0648 \u0628\u0646\u0648\u06cc\u0633<\/p>\n<p>\u0627\u06cc\u0646 test_index_post \u0631\u0648\u0634 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0648\u0627\u0642\u0639\u06cc \u0627\u0633\u062a. \u0647\u0646\u06af\u0627\u0645\u06cc \u06a9\u0647 \u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a POST \u0628\u0647 \u0645\u0633\u06cc\u0631 \u0641\u0647\u0631\u0633\u062a \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc \u0634\u0648\u062f\u060c \u0631\u0641\u062a\u0627\u0631 \u0628\u0631\u0646\u0627\u0645\u0647 \u0631\u0627 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0645\u06cc \u06a9\u0646\u062f (\/).<\/p>\n<p>def test_index_post(self):<\/p>\n<p>\u0639\u0645\u0644\u06cc\u0627\u062a \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0631\u0627 \u0645\u0633\u062e\u0631\u0647 \u06a9\u0646\u06cc\u062f<\/p>\n<p>\u0627\u06cc\u0646 patch \u0627\u0632 \u062a\u0627\u0628\u0639 \u0628\u0631\u0627\u06cc \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f insert_one \u0631\u0648\u0634 \u0627\u0632 todos \u0628\u0627 \u06cc\u06a9 MagicMock. \u0627\u06cc\u0646 \u0628\u0647 \u0622\u0632\u0645\u0648\u0646 \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc \u062f\u0647\u062f \u062a\u0627 \u0631\u0641\u062a\u0627\u0631 \u0639\u0645\u0644\u06cc\u0627\u062a \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0631\u0627 \u0628\u062f\u0648\u0646 \u062a\u0639\u0627\u0645\u0644 \u0648\u0627\u0642\u0639\u06cc \u0628\u0627 \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0648\u0627\u0642\u0639\u06cc \u0634\u0628\u06cc\u0647 \u0633\u0627\u0632\u06cc \u06a9\u0646\u062f.<\/p>\n<p>with patch(&#8216;app.todos.insert_one&#8217;, new_callable=MagicMock) as mock_insert_one:<\/p>\n<p>\u06cc\u06a9 \u0632\u0645\u06cc\u0646\u0647 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u062a\u0633\u062a \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f<\/p>\n<p>\u06cc\u06a9 \u0632\u0645\u06cc\u0646\u0647 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0628\u0631\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u06cc\u062c\u0627\u062f \u0645\u06cc \u0634\u0648\u062f app.test_request_context. \u0627\u06cc\u0646 \u0628\u0647 \u0622\u0632\u0645\u0648\u0646 \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc \u062f\u0647\u062f \u062a\u0627 \u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0631\u0627 \u0628\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0634\u0628\u06cc\u0647 \u0633\u0627\u0632\u06cc \u06a9\u0646\u062f.<\/p>\n<p>with app.test_request_context(&#8216;\/&#8217;):<\/p>\n<p>\u0631\u0648\u0634 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0648 \u062f\u0627\u062f\u0647 \u0647\u0627\u06cc \u0641\u0631\u0645 \u0631\u0627 \u062a\u0646\u0638\u06cc\u0645 \u06a9\u0646\u06cc\u062f<\/p>\n<p>\u0631\u0648\u0634 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0631\u0648\u06cc \u00abPOST\u00bb \u0648 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0641\u0631\u0645 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0631\u0648\u06cc \u0641\u0631\u0647\u0646\u06af \u0644\u063a\u062a \u0628\u0627 \u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc \u00ab\u0645\u062d\u062a\u0648\u0627\u00bb \u0648 \u00ab\u062f\u0631\u062c\u0647\u00bb \u062a\u0646\u0638\u06cc\u0645 \u0645\u06cc\u200c\u0634\u0648\u062f.<\/p>\n<p>flask.request.method = &#8216;POST&#8217;<br \/>\nflask.request.form = {&#8216;content&#8217;: &#8216;Test Content&#8217;, &#8216;degree&#8217;: &#8216;Test Degree&#8217;}<\/p>\n<p>\u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a POST \u0628\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0631\u0633\u0627\u0644 \u06a9\u0646\u06cc\u062f<\/p>\n<p>\u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a POST \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 \u0628\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc \u0634\u0648\u062f self.app.post. \u062f\u0627\u062f\u0647 \u0647\u0627\u06cc \u0641\u0631\u0645 \u0628\u0647 \u0639\u0646\u0648\u0627\u0646 \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc \u0634\u0648\u0646\u062f data \u0627\u0633\u062a\u062f\u0644\u0627\u0644<\/p>\n<p>result = self.app.post(&#8216;\/&#8217;, data=flask.request.form)<\/p>\n<p>\u0646\u062a\u0627\u06cc\u062c \u0645\u0648\u0631\u062f \u0627\u0646\u062a\u0638\u0627\u0631 \u0631\u0627 \u062a\u0627\u06cc\u06cc\u062f \u06a9\u0646\u06cc\u062f<\/p>\n<p>\u0627\u06cc\u0646 assertEqual \u0631\u0648\u0634 \u0628\u0631\u0627\u06cc \u0628\u0631\u0631\u0633\u06cc \u0627\u06cc\u0646\u06a9\u0647 \u06a9\u062f \u0648\u0636\u0639\u06cc\u062a \u067e\u0627\u0633\u062e 302 \u0627\u0633\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f assert_called \u0631\u0648\u0634\u06cc \u0628\u0631\u0627\u06cc \u0628\u0631\u0631\u0633\u06cc \u0627\u06cc\u0646\u06a9\u0647 insert_one \u0631\u0648\u0634 \u0646\u0627\u0645\u06cc\u062f\u0647 \u0634\u062f.<\/p>\n<p>self.assertEqual(result.status_code, 302)<br \/>\nmock_insert_one.assert_called()<\/p>\n<p>\u0627\u06cc\u0646 \u062a\u0633\u062a \u062a\u0636\u0645\u06cc\u0646 \u0645\u06cc \u06a9\u0646\u062f \u06a9\u0647 \u0648\u0642\u062a\u06cc \u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a POST \u0628\u0627 \u062f\u0627\u062f\u0647 \u0647\u0627\u06cc \u0641\u0631\u0645 \u0635\u062d\u06cc\u062d \u0628\u0647 \u0645\u0633\u06cc\u0631 \u0641\u0647\u0631\u0633\u062a \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc \u0634\u0648\u062f\u060c \u0628\u0631\u0646\u0627\u0645\u0647 \u0628\u0627 \u06cc\u06a9 \u06a9\u062f \u0648\u0636\u0639\u06cc\u062a 302 \u067e\u0627\u0633\u062e \u0645\u06cc \u062f\u0647\u062f \u0648 \u062f\u0627\u062f\u0647 \u0647\u0627 \u0631\u0627 \u062f\u0631 \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0648\u0627\u0631\u062f \u0645\u06cc \u06a9\u0646\u062f.<\/p>\n<p>\u06a9\u062f \u062a\u0633\u062a \u0634\u0645\u0627 \u0628\u0627\u06cc\u062f \u0686\u06cc\u0632\u06cc \u0634\u0628\u06cc\u0647 \u0628\u0647 \u0632\u06cc\u0631 \u0628\u0627\u0634\u062f:<\/p>\n<p>import unittest<br \/>\nfrom unittest.mock import patch, MagicMock<br \/>\nfrom bson.objectid import ObjectId<br \/>\nfrom app import app, todos<br \/>\nimport mongomock<br \/>\nimport flask<\/p>\n<p>## Create a mock MongoDB instance<br \/>\nmock_db = mongomock.MongoClient().db<\/p>\n<p>class TestApp(unittest.TestCase):<br \/>\n    def setUp(self):<br \/>\n        # Create a test client instance<br \/>\n        self.app = app.test_client()<br \/>\n        # Enable testing mode. Exceptions are propagated rather than handled by the the app&#8217;s error handlers<br \/>\n        self.app.testing = True <\/p>\n<p>    def test_index_post(self):<br \/>\n        # Patch the insert_one method of todos with a MagicMock<br \/>\n        with patch(&#8216;app.todos.insert_one&#8217;, new_callable=MagicMock) as mock_insert_one:<br \/>\n            # Create a test request context for the app<br \/>\n            with app.test_request_context(&#8216;\/&#8217;):<br \/>\n                # Set the request method to &#8216;POST&#8217;<br \/>\n                flask.request.method = &#8216;POST&#8217;<br \/>\n                # Set the request form data<br \/>\n                flask.request.form = {&#8216;content&#8217;: &#8216;Test Content&#8217;, &#8216;degree&#8217;: &#8216;Test Degree&#8217;}<br \/>\n                # Send a POST request to the app<br \/>\n                result = self.app.post(&#8216;\/&#8217;, data=flask.request.form)<br \/>\n                # Assert that the status code of the response is 302<br \/>\n                self.assertEqual(result.status_code, 302)<br \/>\n                # Assert that the insert_one method was called<br \/>\n                mock_insert_one.assert_called()<\/p>\n<p>\u062d\u0627\u0644 \u0628\u0631\u0627\u06cc \u0627\u062c\u0631\u0627\u06cc \u062a\u0633\u062a\u060c \u0645\u062a\u063a\u06cc\u0631 \u0645\u062d\u06cc\u0637\u06cc TESTING=true\u060c Setting \u0631\u0627 \u062a\u0646\u0638\u06cc\u0645 \u06a9\u0646\u06cc\u062f TESTING=True \u0628\u0631\u0646\u0627\u0645\u0647 \u0631\u0627 \u062a\u063a\u06cc\u06cc\u0631 \u0645\u06cc \u062f\u0647\u062f \u062a\u0627 \u0628\u0647 \u062c\u0627\u06cc \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0648\u0627\u0642\u0639\u06cc MongoDB \u0627\u0632 \u06cc\u06a9 \u06a9\u0644\u0627\u06cc\u0646\u062a \u0633\u0627\u062e\u062a\u06af\u06cc MongoDB \u0628\u0631\u0627\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0646\u062f.<\/p>\n<p>\u062d\u0627\u0644\u060c \u0627\u06af\u0631 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0634\u0645\u0627 \u0645\u0648\u0641\u0642\u06cc\u062a \u0622\u0645\u06cc\u0632 \u0628\u0648\u062f\u060c \u0628\u06cc\u0627\u06cc\u06cc\u062f \u0628\u0647 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build \u0628\u0631\u0648\u06cc\u0645.<\/p>\n<p>  \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc Cloud Build<\/p>\n<p>\u0631\u0627\u0647\u0646\u0645\u0627\u06cc \u0627\u062a\u0635\u0627\u0644 Cloud Build \u0631\u0627 \u0628\u0647 \u0645\u062e\u0632\u0646 \u062e\u0648\u062f \u0648 \u0627\u06cc\u0646 \u06cc\u06a9\u06cc \u0628\u0631\u0627\u06cc \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0627\u0648\u0644\u06cc\u0647 \u062f\u0646\u0628\u0627\u0644 \u06a9\u0646\u06cc\u062f.<\/p>\n<p>\u067e\u0633 \u0627\u0632 \u0627\u0646\u062c\u0627\u0645 \u0627\u06cc\u0646 \u06a9\u0627\u0631\u060c \u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f \u0628\u0647 \u0646\u0648\u0634\u062a\u0646 \u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build \u0628\u0631\u0648\u06cc\u0645\u060c \u062c\u0627\u06cc\u06cc \u06a9\u0647 \u0628\u0647 \u0622\u0646 \u062f\u0631 \u0645\u0648\u0631\u062f \u0646\u062d\u0648\u0647 \u0627\u062c\u0631\u0627\u06cc \u062e\u0637 \u0644\u0648\u0644\u0647\u060c \u0645\u0631\u0627\u062d\u0644 \u0645\u0631\u0628\u0648\u0637\u0647\u060c \u0648\u0627\u0628\u0633\u062a\u06af\u06cc \u0647\u0627 \u0648 \u063a\u06cc\u0631\u0647 \u0622\u0645\u0648\u0632\u0634 \u0645\u06cc \u062f\u0647\u06cc\u0645.<\/p>\n<p>  \u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build<\/p>\n<p>\u0641\u0627\u06cc\u0644 Cloud Build Config \u0628\u0647 \u0632\u0628\u0627\u0646 YAML \u0646\u0648\u0634\u062a\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a\u060c \u06cc\u06a9 \u0632\u0628\u0627\u0646 \u0633\u0631\u06cc\u0627\u0644\u200c\u0633\u0627\u0632\u06cc \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0642\u0627\u0628\u0644 \u062e\u0648\u0627\u0646\u062f\u0646 \u0628\u0631\u0627\u06cc \u0627\u0646\u0633\u0627\u0646.<\/p>\n<p>\u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u0628\u062e\u0634 \u0647\u0627\u06cc \u0627\u0635\u0644\u06cc \u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0645\u0627 \u0622\u0645\u062f\u0647 \u0627\u0633\u062a:<\/p>\n<p>\u062a\u0639\u0648\u06cc\u0636 \u0647\u0627: \u0627\u06cc\u0646\u0647\u0627 \u0645\u062a\u063a\u06cc\u0631\u0647\u0627\u06cc \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u062a\u0648\u0633\u0637 \u06a9\u0627\u0631\u0628\u0631 \u0647\u0633\u062a\u0646\u062f \u06a9\u0647 \u0645\u06cc \u062a\u0648\u0627\u0646\u0646\u062f \u062f\u0631 \u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646 \u0634\u0648\u0646\u062f. \u0622\u0646\u0647\u0627 \u062a\u062d\u062a \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0646\u062f substitutions \u06a9\u0644\u06cc\u062f \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0648\u0631\u062f\u060c _REGION\u060c _REPOSITORY\u060c _IMAGE\u060c \u0648 _SEVERITY \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0646\u062f.<\/p>\n<p>substitutions:<br \/>\n  _REGION: us-central1<br \/>\n  _REPOSITORY: from-legacy-to-cloud<br \/>\n  _IMAGE: from-legacy-to-cloud<br \/>\n  _SEVERITY: &#8216;&#8221;CRITICAL|HIGH&#8221;&#8216;<\/p>\n<p>\u0645\u0631\u0627\u062d\u0644: \u0627\u06cc\u0646\u0647\u0627 \u0639\u0645\u0644\u06cc\u0627\u062a\u06cc \u0647\u0633\u062a\u0646\u062f \u06a9\u0647 Cloud Build \u0627\u0646\u062c\u0627\u0645 \u062e\u0648\u0627\u0647\u062f \u062f\u0627\u062f. \u0647\u0631 \u0645\u0631\u062d\u0644\u0647 \u06cc\u06a9 \u0639\u0645\u0644 \u062c\u062f\u0627\u06af\u0627\u0646\u0647 \u0627\u0633\u062a \u0648 \u0628\u0647 \u062a\u0631\u062a\u06cc\u0628\u06cc \u06a9\u0647 \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0646\u062f \u0627\u062c\u0631\u0627 \u0645\u06cc \u0634\u0648\u0646\u062f.<\/p>\n<p>* **Step 0: Install test dependencies**: This step uses a Python 3.10 Docker image to install the test dependencies listed in `docker\/requirements-test.txt`. The `entrypoint` is set to `\/bin\/bash`, which means that the command that follows will be executed in a bash shell. The `args` key specifies the command to be executed, which in this case is a pip install command. The `-c` flag tells bash to read commands from the following string. The `|` character allows us to write multiple commands, which will be executed in order.<\/p>\n<p>    &#8220;`yaml<br \/>\n    &#8211; name: &#8216;python:3.10-slim&#8217;<br \/>\n      entrypoint: &#8216;\/bin\/bash&#8217;<br \/>\n      args:<br \/>\n        &#8211; &#8216;-c&#8217;<br \/>\n        &#8211; |<br \/>\n          pip install &#8211;user -r docker\/requirements-test.txt<br \/>\n      id: &#8216;install-test-dependencies&#8217;<br \/>\n    &#8220;`<\/p>\n<p>* **Step 1: Run unit tests**: This step also uses a Python 3.10 Docker image to run the unit tests defined in [`test.py`](http:\/\/test.py). The `export TESTING=True` command sets an environment variable `TESTING` to `True`, which can be used to change the behavior of the application during testing. The `cd docker` command changes the current directory to `docker`, where the test file is located. The `python -m unittest` [`test.py`](http:\/\/test.py) command runs the unit tests in [`test.py`](http:\/\/test.py).<\/p>\n<p>    &#8220;`yaml<br \/>\n    &#8211; name: &#8216;python:3.10-slim&#8217;<br \/>\n      entrypoint: &#8216;\/bin\/bash&#8217;<br \/>\n      args:<br \/>\n        &#8211; &#8216;-c&#8217;<br \/>\n        &#8211; |<br \/>\n          export TESTING=True<br \/>\n          cd docker<br \/>\n          python -m unittest test.py<br \/>\n      id: &#8216;run-tests&#8217;<br \/>\n    &#8220;`<\/p>\n<p>* **Step 2: Build the Docker image**: This step uses the `docker` Cloud Builder to build a Docker image from the Dockerfile located in the `docker\/` directory. The image is tagged with the commit SHA. The `waitFor` key is used to specify that this step should wait for the `run-tests` step to complete before it starts. The `args` key specifies the command to be executed, which in this case is a docker build command. The `-t` flag is used to name and optionally tag the image in the &#8216;name:tag&#8217; format.<\/p>\n<p>    &#8220;`yaml<br \/>\n    &#8211; name: &#8216;gcr.io\/cloud-builders\/docker&#8217;<br \/>\n      args: [&#8216;build&#8217;, &#8216;-t&#8217;, &#8216;$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA&#8217;, &#8216;docker\/&#8217;]\n      waitFor: [&#8216;run-tests&#8217;]\n      id: &#8216;build-image&#8217;<br \/>\n    &#8220;`<\/p>\n<p>\u0645\u0631\u062d\u0644\u0647 3: \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f \u0648 \u062e\u0644\u0627\u0635\u0647 \u0631\u0627 \u062f\u0631 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0628\u0646\u0648\u06cc\u0633\u06cc\u062f: \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0627\u0632 docker Cloud Builder \u0628\u0631\u0627\u06cc \u0628\u0631\u0631\u0633\u06cc \u062a\u0635\u0648\u06cc\u0631 Docker \u0648 \u0646\u0648\u0634\u062a\u0646 \u062e\u0644\u0627\u0635\u0647 \u062a\u0635\u0648\u06cc\u0631 \u062f\u0631 \u06cc\u06a9 \u0641\u0627\u06cc\u0644. \u062e\u0644\u0627\u0635\u0647 \u062a\u0635\u0648\u06cc\u0631 \u06cc\u06a9 \u0634\u0646\u0627\u0633\u0647 \u0645\u0646\u062d\u0635\u0631 \u0628\u0647 \u0641\u0631\u062f \u0628\u0631\u0627\u06cc \u062a\u0635\u0648\u06cc\u0631 \u0627\u0633\u062a. \u0627\u06cc\u0646 docker image inspect \u062f\u0633\u062a\u0648\u0631 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u062f\u0642\u06cc\u0642 \u062f\u0631 \u0645\u0648\u0631\u062f \u062a\u0635\u0648\u06cc\u0631 \u062f\u0627\u06a9\u0631 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0645\u06cc \u06a9\u0646\u062f. \u0627\u06cc\u0646 &#8211;format \u06af\u0632\u06cc\u0646\u0647 \u0628\u0631\u0627\u06cc \u0642\u0627\u0644\u0628 \u0628\u0646\u062f\u06cc \u062e\u0631\u0648\u062c\u06cc \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0627\u0644\u06af\u0648\u0647\u0627\u06cc Go \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 {{index .RepoTags 0}}@{{.Id}} \u0627\u0644\u06af\u0648 \u0627\u0648\u0644\u06cc\u0646 \u062a\u06af \u062a\u0635\u0648\u06cc\u0631 \u0648 \u0634\u0646\u0627\u0633\u0647 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0645\u06cc \u06a9\u0646\u062f. \u0627\u06cc\u0646 &gt; \u0627\u067e\u0631\u0627\u062a\u0648\u0631 \u062e\u0631\u0648\u062c\u06cc \u0631\u0627 \u0628\u0647 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0647\u062f\u0627\u06cc\u062a \u0645\u06cc \u06a9\u0646\u062f. \u0627\u06cc\u0646 &amp;&amp; \u0627\u0632 \u0639\u0645\u0644\u06af\u0631 \u0628\u0631\u0627\u06cc \u0627\u062c\u0631\u0627\u06cc cat \u0641\u0642\u0637 \u062f\u0631 \u0635\u0648\u0631\u062a\u06cc \u062f\u0633\u062a\u0648\u0631 \u062f\u0647\u06cc\u062f \u06a9\u0647 \u062f\u0633\u062a\u0648\u0631 \u0642\u0628\u0644\u06cc \u0645\u0648\u0641\u0642\u06cc\u062a \u0622\u0645\u06cc\u0632 \u0628\u0627\u0634\u062f.<\/p>\n<p>&#8211; name: &#8216;gcr.io\/cloud-builders\/docker&#8217;<br \/>\n  entrypoint: &#8216;\/bin\/bash&#8217;<br \/>\n  args:<br \/>\n    &#8211; &#8216;-c&#8217;<br \/>\n    &#8211; |<br \/>\n      docker image inspect $_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA &#8211;format &#8216;{{index .RepoTags 0}}@{{.Id}}&#8217; &gt; \/workspace\/image-digest.txt &amp;&amp;<br \/>\n      cat \/workspace\/image-digest.txt<br \/>\n  id: &#8216;inspect-image&#8217;<\/p>\n<p>\u0645\u0631\u062d\u0644\u0647 4: \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0631\u0627\u06cc \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u0627\u0633\u06a9\u0646 \u06a9\u0646\u06cc\u062f: \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0627\u0632 cloud-sdk Cloud Builder \u0628\u0631\u0627\u06cc \u0627\u0633\u06a9\u0646 \u062a\u0635\u0648\u06cc\u0631 Docker \u0628\u0631\u0627\u06cc \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc\u200c\u0647\u0627. \u0634\u0646\u0627\u0633\u0647 \u0627\u0633\u06a9\u0646 \u062f\u0631 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0646\u0648\u0634\u062a\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 gcloud artifacts docker images scan \u062f\u0633\u062a\u0648\u0631 \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0631\u0627\u06cc \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u0627\u0633\u06a9\u0646 \u0645\u06cc\u200c\u06a9\u0646\u062f. \u0627\u06cc\u0646 &#8211;format=&#8221;value(response.scan)&#8221; \u06af\u0632\u06cc\u0646\u0647 \u0628\u0631\u0627\u06cc \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0634\u0646\u0627\u0633\u0647 \u0627\u0633\u06a9\u0646 \u0627\u0632 \u067e\u0627\u0633\u062e \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 &gt; \u0627\u067e\u0631\u0627\u062a\u0648\u0631 \u062e\u0631\u0648\u062c\u06cc \u0631\u0627 \u0628\u0647 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0647\u062f\u0627\u06cc\u062a \u0645\u06cc \u06a9\u0646\u062f.<\/p>\n<p>&#8211; id: scan<br \/>\n  name: gcr.io\/google.com\/cloudsdktool\/cloud-sdk<br \/>\n  entrypoint: \/bin\/bash<br \/>\n  args:<br \/>\n  &#8211; -c<br \/>\n  &#8211; |<br \/>\n    gcloud artifacts docker images scan $_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA \\<br \/>\n    &#8211;format=&#8221;value(response.scan)&#8221; &gt; \/workspace\/scan_id.txt<\/p>\n<p>\u0645\u0631\u062d\u0644\u0647 5: \u0634\u062f\u062a \u0647\u0631 \u06af\u0648\u0646\u0647 \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u06cc\u0627\u0641\u062a \u0634\u062f\u0647 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f: \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0627\u0632 cloud-sdk Cloud Builder \u0628\u0631\u0627\u06cc \u0641\u0647\u0631\u0633\u062a \u06a9\u0631\u062f\u0646 \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc\u200c\u0647\u0627\u06cc \u0645\u0648\u062c\u0648\u062f \u062f\u0631 \u062a\u0635\u0648\u06cc\u0631 Docker \u0648 \u0628\u0631\u0631\u0633\u06cc \u0634\u062f\u062a \u0622\u0646\u0647\u0627. \u062f\u0631 \u0635\u0648\u0631\u062a \u0648\u062c\u0648\u062f \u0647\u0631 \u06af\u0648\u0646\u0647 \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u0628\u0627 \u062a\u0637\u0627\u0628\u0642 \u0634\u062f\u062a _SEVERITY \u067e\u06cc\u062f\u0627 \u0645\u06cc \u0634\u0648\u0646\u062f\u060c \u0633\u0627\u062e\u062a \u0628\u0627 \u0634\u06a9\u0633\u062a \u0645\u0648\u0627\u062c\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 gcloud artifacts docker images list-vulnerabilities \u062f\u0633\u062a\u0648\u0631\u060c \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u0647\u0627\u06cc \u0645\u0648\u062c\u0648\u062f \u062f\u0631 \u062a\u0635\u0648\u06cc\u0631 \u062f\u0627\u06a9\u0631 \u0631\u0627 \u0641\u0647\u0631\u0633\u062a \u0645\u06cc \u06a9\u0646\u062f. \u0627\u06cc\u0646 &#8211;format=&#8221;value(vulnerability.effectiveSeverity)&#8221; \u06af\u0632\u06cc\u0646\u0647 \u0628\u0631\u0627\u06cc \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0634\u062f\u062a \u0647\u0631 \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 grep -Exq $_SEVERITY \u062f\u0633\u062a\u0648\u0631 \u0628\u0631\u0631\u0633\u06cc \u0645\u06cc \u06a9\u0646\u062f \u06a9\u0647 \u0622\u06cc\u0627 \u0647\u0631 \u06cc\u06a9 \u0627\u0632 \u0634\u062f\u062a \u0647\u0627 \u0645\u0637\u0627\u0628\u0642\u062a \u062f\u0627\u0631\u0646\u062f \u06cc\u0627 \u062e\u06cc\u0631 _SEVERITY. \u0627\u06cc\u0646 echo \u062f\u0633\u062a\u0648\u0631 \u06cc\u06a9 \u067e\u06cc\u0627\u0645 \u0631\u0627 \u0686\u0627\u067e \u0645\u06cc \u06a9\u0646\u062f \u0648 exit 1 \u0627\u06af\u0631 \u0645\u0637\u0627\u0628\u0642\u062a \u067e\u06cc\u062f\u0627 \u0634\u0648\u062f\u060c \u062f\u0633\u062a\u0648\u0631 \u0633\u0627\u062e\u062a \u0631\u0627 \u062e\u0627\u062a\u0645\u0647 \u0645\u06cc \u062f\u0647\u062f.<\/p>\n<p>&#8211; id: severity check<br \/>\n  name: gcr.io\/google.com\/cloudsdktool\/cloud-sdk<br \/>\n  entrypoint: \/bin\/bash<br \/>\n  args:<br \/>\n  &#8211; -c<br \/>\n  &#8211; |<br \/>\n    gcloud artifacts docker images list-vulnerabilities $(cat \/workspace\/scan_id.txt) \\<br \/>\n    &#8211;format=&#8221;value(vulnerability.effectiveSeverity)&#8221; | if grep -Exq $_SEVERITY; \\<br \/>\n    then echo &#8216;Failed vulnerability check&#8217; &amp;&amp; exit 1; else exit 0; fi<\/p>\n<p>\u0645\u0631\u062d\u0644\u0647 6: \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0647 Google Cloud Artifact Registry \u0641\u0634\u0627\u0631 \u062f\u0647\u06cc\u062f: \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0627\u0632 docker Cloud Builder \u0628\u0631\u0627\u06cc \u0641\u0634\u0627\u0631 \u062f\u0627\u062f\u0646 \u062a\u0635\u0648\u06cc\u0631 Docker \u0628\u0647 Google Cloud Artifact Registry. \u0627\u06cc\u0646 waitFor \u0627\u0632 \u06a9\u0644\u06cc\u062f \u0628\u0631\u0627\u06cc \u062a\u0639\u06cc\u06cc\u0646 \u0627\u06cc\u0646\u06a9\u0647 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0628\u0627\u06cc\u062f \u0645\u0646\u062a\u0638\u0631 \u0628\u0645\u0627\u0646\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f severity check \u0645\u0631\u062d\u0644\u0647 \u0628\u0631\u0627\u06cc \u062a\u06a9\u0645\u06cc\u0644 \u0642\u0628\u0644 \u0627\u0632 \u0634\u0631\u0648\u0639. \u0627\u06cc\u0646 docker push \u062f\u0633\u062a\u0648\u0631 \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0647 \u06cc\u06a9 \u0645\u062e\u0632\u0646 \u0647\u0644 \u0645\u06cc \u062f\u0647\u062f.<\/p>\n<p>&#8211; name: &#8216;gcr.io\/cloud-builders\/docker&#8217;<br \/>\n  args: [&#8216;push&#8217;, &#8216;$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA&#8217;]\n  id: &#8216;push-image&#8217;<br \/>\n  waitFor: [&#8216;severity check&#8217;]\n<p>\u062a\u0635\u0627\u0648\u06cc\u0631: \u0627\u06cc\u0646 \u06a9\u0644\u06cc\u062f \u062a\u0635\u0627\u0648\u06cc\u0631 Docker \u0631\u0627 \u06a9\u0647 Cloud Build \u0628\u0627\u06cc\u062f \u0628\u0633\u0627\u0632\u062f \u0648 \u0628\u0647 \u0631\u062c\u06cc\u0633\u062a\u0631\u06cc Google Cloud Artifact \u0641\u0634\u0627\u0631 \u062f\u0647\u062f\u060c \u0645\u0634\u062e\u0635 \u0645\u06cc \u06a9\u0646\u062f. \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0648\u0631\u062f\u060c \u062a\u0635\u0648\u06cc\u0631 Docker \u0633\u0627\u062e\u062a\u0647 \u0634\u062f\u0647 \u062f\u0631 \u0645\u0631\u062d\u0644\u0647 2 \u0627\u0633\u062a.<\/p>\n<p>images:<br \/>\n&#8211; &#8216;$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA&#8217;<\/p>\n<p>\u0627\u06cc\u0646 cloudbuild.yaml \u0641\u0627\u06cc\u0644 \u06cc\u06a9 \u062e\u0637 \u0644\u0648\u0644\u0647 \u06a9\u0627\u0645\u0644 CI\/CD \u0631\u0627 \u0628\u0631\u0627\u06cc \u0628\u0631\u0646\u0627\u0645\u0647 \u0645\u0627 \u062a\u0639\u0631\u06cc\u0641 \u0645\u06cc \u06a9\u0646\u062f. \u0648\u0627\u0628\u0633\u062a\u06af\u06cc\u200c\u0647\u0627\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0631\u0627 \u0646\u0635\u0628 \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0622\u0632\u0645\u0627\u06cc\u0634\u200c\u0647\u0627\u06cc \u0648\u0627\u062d\u062f \u0631\u0627 \u0627\u062c\u0631\u0627 \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u06cc\u06a9 \u062a\u0635\u0648\u06cc\u0631 Docker \u0645\u06cc\u200c\u0633\u0627\u0632\u062f\u060c \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0628\u0627\u0632\u0631\u0633\u06cc \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u0627\u0633\u06a9\u0646 \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0634\u062f\u062a \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc\u200c\u0647\u0627\u06cc \u06cc\u0627\u0641\u062a \u0634\u062f\u0647 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u0645\u06cc\u200c\u06a9\u0646\u062f \u0648 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0628\u0647 \u0631\u062c\u06cc\u0633\u062a\u0631\u06cc Google Cloud Artifact \u0645\u0646\u062a\u0642\u0644 \u0645\u06cc\u200c\u06a9\u0646\u062f. \u0627\u06cc\u0646 \u062e\u0637 \u0644\u0648\u0644\u0647 \u062a\u0636\u0645\u06cc\u0646 \u0645\u06cc \u06a9\u0646\u062f \u06a9\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0634\u062f\u0647\u060c \u0627\u06cc\u0645\u0646 \u0648 \u0622\u0645\u0627\u062f\u0647 \u0627\u0633\u062a\u0642\u0631\u0627\u0631 \u0627\u0633\u062a.<\/p>\n<p>\u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u06a9\u0627\u0645\u0644 \u0628\u0627\u06cc\u062f \u0628\u0647 \u0634\u06a9\u0644 \u0632\u06cc\u0631 \u0628\u0627\u0634\u062f:<\/p>\n<p>substitutions:<br \/>\n  _REGION: us-central1<br \/>\n  _REPOSITORY: from-legacy-to-cloud<br \/>\n  _IMAGE: from-legacy-to-cloud<br \/>\n  _SEVERITY: &#8216;&#8221;CRITICAL|HIGH&#8221;&#8216;<\/p>\n<p>steps:<br \/>\n# Step 0: Install test dependencies<br \/>\n&#8211; id: &#8216;install-test-dependencies&#8217;<br \/>\n  name: &#8216;python:3.10-slim&#8217;<br \/>\n  entrypoint: &#8216;\/bin\/bash&#8217;<br \/>\n  args:<br \/>\n    &#8211; &#8216;-c&#8217;<br \/>\n    &#8211; |<br \/>\n      pip install &#8211;user -r docker\/requirements-test.txt<\/p>\n<p># Step 1: Run unit tests<br \/>\n&#8211; id: &#8216;run-tests&#8217;<br \/>\n  name: &#8216;python:3.10-slim&#8217;<br \/>\n  entrypoint: &#8216;\/bin\/bash&#8217;<br \/>\n  args:<br \/>\n    &#8211; &#8216;-c&#8217;<br \/>\n    &#8211; |<br \/>\n      export TESTING=True<br \/>\n      cd docker<br \/>\n      python -m unittest test.py<\/p>\n<p># Step 2: Build the Docker image<br \/>\n&#8211; id: &#8216;build-image&#8217;<br \/>\n  name: &#8216;gcr.io\/cloud-builders\/docker&#8217;<br \/>\n  args: [&#8216;build&#8217;, &#8216;-t&#8217;, &#8216;$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA&#8217;, &#8216;docker\/&#8217;]\n  waitFor: [&#8216;run-tests&#8217;]\n<p># Step 3: Inspect the Docker image and write the digest to a file.<br \/>\n&#8211; id: &#8216;inspect-image&#8217;<br \/>\n  name: &#8216;gcr.io\/cloud-builders\/docker&#8217;<br \/>\n  entrypoint: &#8216;\/bin\/bash&#8217;<br \/>\n  args:<br \/>\n    &#8211; &#8216;-c&#8217;<br \/>\n    &#8211; |<br \/>\n      docker image inspect $_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA &#8211;format &#8216;{{index .RepoTags 0}}@{{.Id}}&#8217; &gt; \/workspace\/image-digest.txt &amp;&amp;<br \/>\n      cat \/workspace\/image-digest.txt<\/p>\n<p># Step 4: Scan the Docker image for vulnerabilities<br \/>\n&#8211; id: scan<br \/>\n  name: gcr.io\/google.com\/cloudsdktool\/cloud-sdk<br \/>\n  entrypoint: \/bin\/bash<br \/>\n  args:<br \/>\n  &#8211; -c<br \/>\n  &#8211; |<br \/>\n    gcloud artifacts docker images scan $_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA \\<br \/>\n    &#8211;format=&#8221;value(response.scan)&#8221; &gt; \/workspace\/scan_id.txt<\/p>\n<p># Step 5: Check the severity of any vulnerabilities found<br \/>\n&#8211; id: severity check<br \/>\n  name: gcr.io\/google.com\/cloudsdktool\/cloud-sdk<br \/>\n  entrypoint: \/bin\/bash<br \/>\n  args:<br \/>\n  &#8211; -c<br \/>\n  &#8211; |<br \/>\n    gcloud artifacts docker images list-vulnerabilities $(cat \/workspace\/scan_id.txt) \\<br \/>\n    &#8211;format=&#8221;value(vulnerability.effectiveSeverity)&#8221; | if grep -Exq $_SEVERITY; \\<br \/>\n    then echo &#8216;Failed vulnerability check&#8217; &amp;&amp; exit 1; else exit 0; fi<\/p>\n<p># Step 6: Push the Docker image to Google Cloud Artifact Registry<br \/>\n&#8211; id: &#8216;push-image&#8217;<br \/>\n  name: &#8216;gcr.io\/cloud-builders\/docker&#8217;<br \/>\n  args: [&#8216;push&#8217;, &#8216;$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA&#8217;]\n  waitFor: [&#8216;severity check&#8217;]\n<p>images:<br \/>\n&#8211; &#8216;$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA&#8217;<\/p>\n<p>  \u0645\u0634\u0627\u0647\u062f\u0647 \u0646\u062a\u0627\u06cc\u062c \u0633\u0627\u062e\u062a<\/p>\n<p>\u0627\u06a9\u0646\u0648\u0646\u060c \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u062e\u0648\u062f \u0631\u0627 \u0645\u062a\u0639\u0647\u062f \u0648 \u0641\u0634\u0627\u0631 \u062f\u0647\u06cc\u062f. \u0627\u06af\u0631 \u0645\u062d\u0631\u06a9 \u0647\u0627\u06cc \u0633\u0627\u062e\u062a \u0627\u0628\u0631 \u0628\u0647 \u062f\u0631\u0633\u062a\u06cc \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0634\u062f\u0647 \u0628\u0627\u0634\u0646\u062f\u060c \u0633\u0627\u062e\u062a \u0628\u0627\u06cc\u062f \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc \u0634\u0648\u062f. \u0628\u0647 Google Cloud Console \u0645\u062a\u0635\u0644 \u0634\u0648\u06cc\u062f\u060c \u0628\u0631\u0627\u06cc \u0645\u0634\u0627\u0647\u062f\u0647 \u0633\u0627\u062e\u062a\u200c\u0647\u0627\u06cc \u062e\u0648\u062f \u0628\u0647 Cloud Build > History \u0628\u0631\u0648\u06cc\u062f.<\/p>\n<p>\u062f\u0631 \u0635\u0648\u0631\u062a \u0639\u062f\u0645 \u0645\u0648\u0641\u0642\u06cc\u062a\u060c \u0631\u0648\u06cc \u0622\u0646 \u06a9\u0644\u06cc\u06a9 \u06a9\u0646\u06cc\u062f \u062a\u0627 \u067e\u06cc\u0627\u0645 \u0647\u0627\u06cc \u062e\u0637\u0627 \u0631\u0627 \u0628\u0628\u06cc\u0646\u06cc\u062f \u0648 \u0628\u0631\u0627\u06cc \u0631\u0641\u0639 \u0645\u0634\u06a9\u0644\u0627\u062a \u0639\u06cc\u0628 \u06cc\u0627\u0628\u06cc \u06a9\u0646\u06cc\u062f. \u067e\u0633 \u0627\u0632 \u0645\u0648\u0641\u0642\u06cc\u062a \u062f\u0631 \u0633\u0627\u062e\u062a\u060c \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u0647 \u0631\u062c\u06cc\u0633\u062a\u0631\u06cc Artifact \u062f\u0633\u062a\u0631\u0633\u06cc \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f \u0648 \u062a\u0635\u0648\u06cc\u0631 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u0634\u0627\u0647\u062f\u0647 \u06a9\u0646\u06cc\u062f.<\/p>\n<p>  \u0628\u0639\u062f\u0634 \u0686\u06cc\u061f<\/p>\n<p>\u062e\u0648\u0628\u060c \u0627\u06cc\u0646 \u0645\u0642\u0627\u0644\u0647 \u0631\u0627 \u0628\u0647 \u067e\u0627\u06cc\u0627\u0646 \u0645\u06cc \u0631\u0633\u0627\u0646\u062f. \u062f\u0631 \u0642\u0633\u0645\u062a \u0628\u0639\u062f\u06cc\u060c \u0645\u0627 \u0628\u0647 \u0627\u0633\u062a\u0642\u0631\u0627\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 &#8211; \u0628\u062e\u0634 CD &#8211; \u062e\u0648\u0627\u0647\u06cc\u0645 \u067e\u0631\u062f\u0627\u062e\u062a. \u067e\u0633 \u0627\u0632 \u0627\u0633\u06a9\u0646 \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u062a\u0635\u0627\u0648\u06cc\u0631 \u06a9\u0627\u0646\u062a\u06cc\u0646\u0631\u060c \u0645\u0627 \u0633\u06cc\u0627\u0633\u062a\u200c\u0647\u0627\u06cc \u0627\u0645\u0646\u06cc\u062a\u06cc \u0631\u0627 \u0627\u0632 \u0637\u0631\u06cc\u0642 \u0645\u062c\u0648\u0632 \u0628\u0627\u06cc\u0646\u0631\u06cc \u0627\u0639\u0645\u0627\u0644 \u0645\u06cc\u200c\u06a9\u0646\u06cc\u0645 \u06a9\u0647 \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc\u200c\u062f\u0647\u062f \u0641\u0642\u0637 \u062a\u0635\u0627\u0648\u06cc\u0631 \u062a\u0623\u06cc\u06cc\u062f \u0634\u062f\u0647\/\u0645\u0639\u062a\u0645\u062f \u062f\u0631 Cloud Run \u0645\u0633\u062a\u0642\u0631 \u0634\u0648\u0646\u062f. \u0627\u0645\u0627 \u0642\u0628\u0644 \u0627\u0632 \u0622\u0646\u060c \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 Mongo \u062e\u0648\u062f \u0631\u0627 \u0628\u0647 Google Firestore \u0645\u0646\u062a\u0642\u0644 \u0645\u06cc \u06a9\u0646\u06cc\u0645. \u067e\u0633 \u0627\u0632 \u0622\u0646\u060c \u0645\u0627 \u0628\u0631\u0646\u0627\u0645\u0647 \u062e\u0648\u062f \u0631\u0627 \u062f\u0631 Cloud Run \u0645\u0633\u062a\u0642\u0631 \u0645\u06cc \u06a9\u0646\u06cc\u0645 \u0648 \u0622\u0646 \u0631\u0627 \u0628\u0647 Firestore \u0645\u062a\u0635\u0644 \u0645\u06cc \u06a9\u0646\u06cc\u0645 \u062a\u0627 \u06a9\u0627\u0645\u0644\u0627\u064b \u0639\u0645\u0644\u06cc\u0627\u062a\u06cc \u0634\u0648\u062f.<\/p>\n<p>\u0634\u0645\u0627 \u0631\u0627 \u062f\u0631 \u0645\u0642\u0627\u0644\u0647 \u0628\u0639\u062f\u06cc \u0645\u06cc \u0628\u06cc\u0646\u06cc\u0645. \u062a\u0627 \u0622\u0646 \u0632\u0645\u0627\u0646\u060c \u0645\u0646 \u062f\u0631 \u0634\u0628\u06a9\u0647 \u0647\u0627\u06cc \u0627\u062c\u062a\u0645\u0627\u0639\u06cc (\u0645\u0646 \u062f\u0631 \u0644\u06cc\u0646\u06a9\u062f\u06cc\u0646 \u0641\u0639\u0627\u0644 \u062a\u0631 \u0647\u0633\u062a\u0645) \u0628\u0631\u0627\u06cc \u0647\u0631\u06af\u0648\u0646\u0647 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u06cc\u0627 \u067e\u06cc\u0634\u0646\u0647\u0627\u062f \u0627\u0636\u0627\u0641\u06cc \u062f\u0631 \u062f\u0633\u062a\u0631\u0633 \u0647\u0633\u062a\u0645. \u0628\u0627 \u062a\u0634\u06a9\u0631 \u0628\u0631\u0627\u06cc \u062e\u0648\u0627\u0646\u062f\u0646!<\/p>\n<blockquote>\n<p><strong>\u062a\u0648\u062c\u0647:<\/strong> \u0627\u06cc\u0646 \u0645\u0642\u0627\u0644\u0647 \u062f\u0631 \u0627\u0628\u062a\u062f\u0627 \u062f\u0631 \u062a\u0627\u0631\u06cc\u062e \u0645\u0646\u062a\u0634\u0631 \u0634\u062f\u0647 \u0627\u0633\u062a <br \/>\n25 \u062f\u0633\u0627\u0645\u0628\u0631 2023 \u0627\u06cc\u0646\u062c\u0627. \u0628\u0631\u0627\u06cc \u062f\u0633\u062a\u06cc\u0627\u0628\u06cc \u0628\u0647 \u0645\u062e\u0627\u0637\u0628\u0627\u0646 \u0628\u06cc\u0634\u062a\u0631 \u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u0628\u0627\u0632\u0646\u0634\u0631 \u0634\u062f\u0647 \u0627\u0633\u062a.<\/p>\n<\/blockquote>\n<p><\/p>\n<p>\u0628\u0647 \u0642\u0633\u0645\u062a \u0633\u0648\u0645 \u0627\u06cc\u0646 \u0633\u0631\u06cc\u0627\u0644 \u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f! \u062f\u0631 \u0627\u06cc\u0646 \u0628\u062e\u0634\u060c \u0628\u0647 \u0622\u0632\u0645\u0627\u06cc\u0634\u200c\u0647\u0627 \u0648 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u062e\u0637 \u0644\u0648\u0644\u0647 \u062f\u0631 Google Cloud \u0645\u06cc\u200c\u067e\u0631\u062f\u0627\u0632\u06cc\u0645\u060c \u0628\u0647\u200c\u0648\u06cc\u0698\u0647 \u0628\u0631 \u0631\u0648\u06cc \u06cc\u06a9\u067e\u0627\u0631\u0686\u0647\u200c\u0633\u0627\u0632\u06cc \u0645\u062f\u0627\u0648\u0645 \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 Cloud Build\u060c \u0627\u0633\u06a9\u0646\u0631 \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc \u0648 \u062b\u0628\u062a \u0645\u0635\u0646\u0648\u0639 \u062a\u0645\u0631\u06a9\u0632 \u0645\u06cc\u200c\u06a9\u0646\u06cc\u0645. \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u0645\u062e\u0632\u0646 \u067e\u0631\u0648\u0698\u0647 \u0631\u0627 \u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u067e\u06cc\u062f\u0627 \u06a9\u0646\u06cc\u062f\u060c \u06cc\u0627 \u062f\u0631 \u0635\u0648\u0631\u062a \u062a\u0645\u0627\u06cc\u0644\u060c \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u067e\u0631\u0648\u0698\u0647 \u062e\u0648\u062f \u0631\u0627 \u0628\u06cc\u0627\u0648\u0631\u06cc\u062f.<\/p>\n<p>\u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f \u0634\u0645\u0627 \u0631\u0627 \u0627\u0632 \u0637\u0631\u06cc\u0642 \u062e\u0637 \u0644\u0648\u0644\u0647 \u0631\u0627\u0647\u0646\u0645\u0627\u06cc\u06cc \u06a9\u0646\u0645. \u0628\u0627 \u0647\u0631 \u0641\u0634\u0627\u0631 \u062f\u0627\u062f\u0646 \u0628\u0647 \u0634\u0627\u062e\u0647 \u0627\u0635\u0644\u06cc\u060c Cloud Build \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc \u0645\u06cc \u0634\u0648\u062f. \u0627\u0628\u062a\u062f\u0627 \u062a\u0633\u062a \u0647\u0627\u06cc \u0648\u0627\u062d\u062f \u0631\u0627 \u0631\u0648\u06cc \u06a9\u062f \u0627\u062c\u0631\u0627 \u0645\u06cc \u06a9\u0646\u062f. \u062f\u0631 \u0635\u0648\u0631\u062a \u0645\u0648\u0641\u0642\u06cc\u062a \u0622\u0645\u06cc\u0632 \u0628\u0648\u062f\u0646 \u062a\u0633\u062a \u0647\u0627\u060c \u0627\u0642\u062f\u0627\u0645 \u0628\u0647 \u0633\u0627\u062e\u062a \u062a\u0635\u0648\u06cc\u0631 \u0645\u06cc \u06a9\u0646\u062f. \u067e\u0633 \u0627\u0632 \u0633\u0627\u062e\u062a\u0647 \u0634\u062f\u0646 \u062a\u0635\u0648\u06cc\u0631\u060c Cloud Build \u0627\u0633\u06a9\u0646\u0631 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0641\u0631\u0627\u062e\u0648\u0627\u0646\u06cc \u0645\u06cc \u06a9\u0646\u062f \u062a\u0627 \u0627\u0632 \u0639\u0627\u0631\u06cc \u0628\u0648\u062f\u0646 \u0622\u0646 \u0627\u0632 \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u0627\u0637\u0645\u06cc\u0646\u0627\u0646 \u062d\u0627\u0635\u0644 \u06a9\u0646\u062f. \u0627\u06af\u0631 \u0647\u0645\u0647 \u0686\u06cc\u0632 \u062e\u0648\u0628 \u0628\u0627\u0634\u062f\u060c \u062a\u0635\u0648\u06cc\u0631 \u0627\u0631\u0633\u0627\u0644 \u0634\u062f\u0647 \u0648 \u062f\u0631 \u0622\u0631\u062a\u06cc\u0641\u06a9\u062a \u0631\u062c\u06cc\u0633\u062a\u0631\u06cc \u0630\u062e\u06cc\u0631\u0647 \u0645\u06cc \u0634\u0648\u062f \u0648 \u0622\u0645\u0627\u062f\u0647 \u0627\u0633\u062a\u0642\u0631\u0627\u0631 \u0627\u0633\u062a. \u0627\u0645\u0627 \u0628\u0631\u0627\u06cc \u0627\u06cc\u0646 \u0645\u0642\u0627\u0644\u0647\u060c \u0645\u0627 \u0641\u0642\u0637 \u0628\u0631 \u0631\u0648\u06cc \u0628\u062e\u0634 CI \u062a\u0645\u0631\u06a9\u0632 \u062e\u0648\u0627\u0647\u06cc\u0645 \u06a9\u0631\u062f. \u0628\u06cc\u0627\u06cc\u06cc\u062f \u0628\u0627 \u0622\u0632\u0645\u0627\u06cc\u0634\u0627\u062a \u0634\u0631\u0648\u0639 \u06a9\u0646\u06cc\u0645.<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 counter-hierarchy ez-toc-counter-rtl ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">\u0641\u0647\u0631\u0633\u062a \u0645\u0637\u0627\u0644\u0628<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/nabfollower.com\/blog\/from-legacy-to-cloud-serverless-part-3-4abm\/#%D9%88%D8%A7%D8%AD%D8%AF_%D8%AA%D8%B3%D8%AA\" >\u0648\u0627\u062d\u062f \u062a\u0633\u062a<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/nabfollower.com\/blog\/from-legacy-to-cloud-serverless-part-3-4abm\/#%D8%B1%D8%A7%D9%87_%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C_Cloud_Build\" >\u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc Cloud Build<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/nabfollower.com\/blog\/from-legacy-to-cloud-serverless-part-3-4abm\/#%D9%81%D8%A7%DB%8C%D9%84_%D9%BE%DB%8C%DA%A9%D8%B1%D8%A8%D9%86%D8%AF%DB%8C_Cloud_Build\" >\u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/nabfollower.com\/blog\/from-legacy-to-cloud-serverless-part-3-4abm\/#%D9%85%D8%B4%D8%A7%D9%87%D8%AF%D9%87_%D9%86%D8%AA%D8%A7%DB%8C%D8%AC_%D8%B3%D8%A7%D8%AE%D8%AA\" >\u0645\u0634\u0627\u0647\u062f\u0647 \u0646\u062a\u0627\u06cc\u062c \u0633\u0627\u062e\u062a<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/nabfollower.com\/blog\/from-legacy-to-cloud-serverless-part-3-4abm\/#%D8%A8%D8%B9%D8%AF%D8%B4_%DA%86%DB%8C%D8%9F\" >\u0628\u0639\u062f\u0634 \u0686\u06cc\u061f<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"%D9%88%D8%A7%D8%AD%D8%AF_%D8%AA%D8%B3%D8%AA\"><\/span>\n<p>  \u0648\u0627\u062d\u062f \u062a\u0633\u062a<br \/>\n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>\u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u06a9\u062f\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0642\u0635\u062f \u0622\u0632\u0645\u0627\u06cc\u0634 \u0622\u0646 \u0631\u0627 \u062f\u0627\u0631\u06cc\u0645\n<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">flask<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Flask<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">pymongo<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">MongoClient<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">flask<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Flask<\/span><span class=\"p\">,<\/span> <span class=\"n\">render_template<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">,<\/span> <span class=\"n\">url_for<\/span><span class=\"p\">,<\/span> <span class=\"n\">redirect<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">bson.objectid<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ObjectId<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">mongomock<\/span>\n\n\n\n<span class=\"n\">app<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Flask<\/span><span class=\"p\">(<\/span><span class=\"n\">__name__<\/span><span class=\"p\">,<\/span> <span class=\"n\">template_folder<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">templates<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">TESTING<\/span><span class=\"sh\">'<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"n\">mongomock<\/span><span class=\"p\">.<\/span><span class=\"nc\">MongoClient<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">MongoClient<\/span><span class=\"p\">(<\/span><span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">MONGO_URI<\/span><span class=\"sh\">'<\/span><span class=\"p\">])<\/span>\n\n\n<span class=\"n\">db<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"p\">.<\/span><span class=\"n\">flask_db<\/span>\n<span class=\"n\">todos<\/span> <span class=\"o\">=<\/span> <span class=\"n\">db<\/span><span class=\"p\">.<\/span><span class=\"n\">todos<\/span>\n\n\n<span class=\"nd\">@app.route<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">methods<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">GET<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">POST<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">index<\/span><span class=\"p\">():<\/span>\n    <span class=\"k\">if<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">method<\/span><span class=\"o\">==<\/span><span class=\"sh\">'<\/span><span class=\"s\">POST<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">content<\/span> <span class=\"o\">=<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">form<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">content<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n        <span class=\"n\">degree<\/span> <span class=\"o\">=<\/span> <span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">form<\/span><span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">degree<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n        <span class=\"n\">todos<\/span><span class=\"p\">.<\/span><span class=\"nf\">insert_one<\/span><span class=\"p\">({<\/span><span class=\"sh\">'<\/span><span class=\"s\">content<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">content<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">degree<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"n\">degree<\/span><span class=\"p\">})<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nf\">redirect<\/span><span class=\"p\">(<\/span><span class=\"nf\">url_for<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">index<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span>\n\n    <span class=\"n\">all_todos<\/span> <span class=\"o\">=<\/span> <span class=\"n\">todos<\/span><span class=\"p\">.<\/span><span class=\"nf\">find<\/span><span class=\"p\">()<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nf\">render_template<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">index.html<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">todos<\/span><span class=\"o\">=<\/span><span class=\"n\">all_todos<\/span><span class=\"p\">)<\/span>\n\n\n<span class=\"nd\">@app.post<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">\/&lt;id&gt;\/delete\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">delete<\/span><span class=\"p\">(<\/span><span class=\"nb\">id<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">todos<\/span><span class=\"p\">.<\/span><span class=\"nf\">delete_one<\/span><span class=\"p\">({<\/span><span class=\"sh\">\"<\/span><span class=\"s\">_id<\/span><span class=\"sh\">\"<\/span><span class=\"p\">:<\/span> <span class=\"nc\">ObjectId<\/span><span class=\"p\">(<\/span><span class=\"nb\">id<\/span><span class=\"p\">)})<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nf\">redirect<\/span><span class=\"p\">(<\/span><span class=\"nf\">url_for<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">index<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span>\n<\/code><\/pre>\n<\/div>\n<p>\u0628\u0631\u0627\u06cc \u062a\u0648\u0636\u06cc\u062d \u06a9\u062f \u0628\u0647 \u0645\u0642\u0627\u0644\u0647 \u0627\u0648\u0644 \u0627\u06cc\u0646 \u0645\u062c\u0645\u0648\u0639\u0647 \u0645\u0631\u0627\u062c\u0639\u0647 \u06a9\u0646\u06cc\u062f.<\/p>\n<p>\u062d\u0627\u0644\u0627 \u0628\u06cc\u0627\u06cc\u06cc\u062f \u0628\u0647 \u0645\u0631\u062d\u0644\u0647 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0628\u0631\u0648\u06cc\u0645<\/p>\n<p>\u0627\u06cc\u0646 \u062a\u0633\u062a \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 \u062f\u0627\u062e\u0644\u06cc \u067e\u0627\u06cc\u062a\u0648\u0646 \u0646\u0648\u0634\u062a\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a <code>unittest<\/code> \u0645\u0627\u0698\u0648\u0644\u060c \u06a9\u0647 \u0686\u0627\u0631\u0686\u0648\u0628\u06cc \u0628\u0631\u0627\u06cc \u0646\u0648\u0634\u062a\u0646 \u0648 \u0627\u062c\u0631\u0627\u06cc \u062a\u0633\u062a \u0647\u0627 \u0641\u0631\u0627\u0647\u0645 \u0645\u06cc \u06a9\u0646\u062f.<\/p>\n<ol>\n<li>\n<p><strong>\u0645\u0627\u0698\u0648\u0644 \u0647\u0627\u06cc \u0644\u0627\u0632\u0645 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f \u0648 \u06cc\u06a9 \u0646\u0645\u0648\u0646\u0647 \u0633\u0627\u062e\u062a\u06af\u06cc MongoDB \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f<\/strong><\/p>\n<p>\u062a\u0633\u062a \u0628\u0627 \u0648\u0627\u0631\u062f \u06a9\u0631\u062f\u0646 \u0645\u0627\u0698\u0648\u0644 \u0647\u0627\u06cc \u0644\u0627\u0632\u0645 \u0622\u063a\u0627\u0632 \u0645\u06cc \u0634\u0648\u062f. <code>unittest<\/code> \u0686\u0627\u0631\u0686\u0648\u0628 \u062a\u0633\u062a \u0627\u0633\u062a\u060c <code>patch<\/code> \u0648 <code>MagicMock<\/code> \u0627\u0632 <code>unittest.mock<\/code> \u0628\u0631\u0627\u06cc \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc \u0628\u062e\u0634 \u0647\u0627\u06cc\u06cc \u0627\u0632 \u0633\u06cc\u0633\u062a\u0645 \u06a9\u0647 \u062f\u0631 \u062d\u0627\u0644 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0622\u0646\u0647\u0627 \u0647\u0633\u062a\u06cc\u062f \u0628\u0627 \u0627\u0634\u06cc\u0627\u0621 \u0633\u0627\u062e\u062a\u06af\u06cc \u0648 <code>ObjectId<\/code> \u0627\u0632 <code>bson.objectid<\/code> \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u0634\u0646\u0627\u0633\u0647 \u0647\u0627\u06cc \u0645\u0646\u062d\u0635\u0631 \u0628\u0647 \u0641\u0631\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 <code>app<\/code> \u0648 <code>todos<\/code> \u0627\u0632 \u06a9\u0634\u0648\u0631 \u0648\u0627\u0631\u062f \u0645\u06cc \u0634\u0648\u0646\u062f <code>app.py<\/code> \u0641\u0627\u06cc\u0644 <code>mongomock<\/code> \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u0646\u0645\u0648\u0646\u0647 MongoDB \u0633\u0627\u062e\u062a\u06af\u06cc \u0628\u0631\u0627\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f \u0648 <code>flask<\/code> \u0628\u0631\u0627\u06cc \u062f\u0633\u062a\u06a9\u0627\u0631\u06cc \u0632\u0645\u06cc\u0646\u0647 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u062f\u0631 \u0637\u0648\u0644 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f.\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">unittest<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">unittest.mock<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">patch<\/span><span class=\"p\">,<\/span> <span class=\"n\">MagicMock<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">bson.objectid<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ObjectId<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">app<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">app<\/span><span class=\"p\">,<\/span> <span class=\"n\">todos<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">mongomock<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">flask<\/span>\n\n<span class=\"n\">mock_db<\/span> <span class=\"o\">=<\/span> <span class=\"n\">mongomock<\/span><span class=\"p\">.<\/span><span class=\"nc\">MongoClient<\/span><span class=\"p\">().<\/span><span class=\"n\">db<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0645\u0648\u0631\u062f \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0631\u0627 \u062a\u0639\u0631\u06cc\u0641 \u06a9\u0646\u06cc\u062f<\/strong><\/p>\n<p>\u06cc\u06a9 \u0645\u0648\u0631\u062f \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0628\u0627 \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u06a9\u0644\u0627\u0633 \u062c\u062f\u06cc\u062f \u06a9\u0647 \u0627\u0632 \u0622\u0646 \u0627\u0631\u062b \u0645\u06cc \u0628\u0631\u062f\u060c \u062a\u0639\u0631\u06cc\u0641 \u0645\u06cc \u0634\u0648\u062f <code>unittest.TestCase<\/code>. \u0627\u06cc\u0646 \u06a9\u0644\u0627\u0633 \u062d\u0627\u0648\u06cc \u0645\u062a\u062f\u0647\u0627\u06cc\u06cc \u062e\u0648\u0627\u0647\u062f \u0628\u0648\u062f \u06a9\u0647 \u062a\u0633\u062a \u0647\u0627\u06cc \u0641\u0631\u062f\u06cc \u0631\u0627 \u0646\u0634\u0627\u0646 \u0645\u06cc \u062f\u0647\u0646\u062f.\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"n\">class<\/span><span class=\"err\">\u00a0<\/span><span class=\"nc\">TestApp<\/span><span class=\"p\">(<\/span><span class=\"n\">unittest<\/span><span class=\"p\">.<\/span><span class=\"n\">TestCase<\/span><span class=\"p\">):<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0645\u062d\u06cc\u0637 \u062a\u0633\u062a \u0631\u0627 \u062a\u0646\u0638\u06cc\u0645 \u06a9\u0646\u06cc\u062f<\/strong><\/p>\n<p>\u0627\u06cc\u0646 <code>setUp<\/code> \u0645\u062a\u062f \u0631\u0648\u0634 \u062e\u0627\u0635\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0642\u0628\u0644 \u0627\u0632 \u0647\u0631 \u062a\u0633\u062a \u0627\u062c\u0631\u0627 \u0645\u06cc \u0634\u0648\u062f. \u062f\u0631 \u0627\u06cc\u0646\u062c\u0627\u060c \u0627\u0632 \u0622\u0646 \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u0646\u0645\u0648\u0646\u0647 \u0645\u0634\u062a\u0631\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0627\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 Flask \u0648 \u0641\u0639\u0627\u0644 \u06a9\u0631\u062f\u0646 \u062d\u0627\u0644\u062a \u062a\u0633\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc\u200c\u0634\u0648\u062f.\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"k\">def<\/span> <span class=\"nf\">setUp<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">app<\/span> <span class=\"o\">=<\/span> <span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"nf\">test_client<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"n\">testing<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">True<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u062a\u0633\u062a \u0631\u0648 \u0628\u0646\u0648\u06cc\u0633<\/strong><\/p>\n<p>\u0627\u06cc\u0646 <code>test_index_post<\/code> \u0631\u0648\u0634 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0648\u0627\u0642\u0639\u06cc \u0627\u0633\u062a. \u0647\u0646\u06af\u0627\u0645\u06cc \u06a9\u0647 \u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a POST \u0628\u0647 \u0645\u0633\u06cc\u0631 \u0641\u0647\u0631\u0633\u062a \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc \u0634\u0648\u062f\u060c \u0631\u0641\u062a\u0627\u0631 \u0628\u0631\u0646\u0627\u0645\u0647 \u0631\u0627 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0645\u06cc \u06a9\u0646\u062f (<code>\/<\/code>).\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"k\">def<\/span> <span class=\"nf\">test_index_post<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0639\u0645\u0644\u06cc\u0627\u062a \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0631\u0627 \u0645\u0633\u062e\u0631\u0647 \u06a9\u0646\u06cc\u062f<\/strong><\/p>\n<p>\u0627\u06cc\u0646 <code>patch<\/code> \u0627\u0632 \u062a\u0627\u0628\u0639 \u0628\u0631\u0627\u06cc \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f <code>insert_one<\/code> \u0631\u0648\u0634 \u0627\u0632 <code>todos<\/code> \u0628\u0627 \u06cc\u06a9 <code>MagicMock<\/code>. \u0627\u06cc\u0646 \u0628\u0647 \u0622\u0632\u0645\u0648\u0646 \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc \u062f\u0647\u062f \u062a\u0627 \u0631\u0641\u062a\u0627\u0631 \u0639\u0645\u0644\u06cc\u0627\u062a \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0631\u0627 \u0628\u062f\u0648\u0646 \u062a\u0639\u0627\u0645\u0644 \u0648\u0627\u0642\u0639\u06cc \u0628\u0627 \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0648\u0627\u0642\u0639\u06cc \u0634\u0628\u06cc\u0647 \u0633\u0627\u0632\u06cc \u06a9\u0646\u062f.\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"k\">with<\/span> <span class=\"nf\">patch<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">app.todos.insert_one<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">new_callable<\/span><span class=\"o\">=<\/span><span class=\"n\">MagicMock<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">mock_insert_one<\/span><span class=\"p\">:<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u06cc\u06a9 \u0632\u0645\u06cc\u0646\u0647 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u062a\u0633\u062a \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f<\/strong><\/p>\n<p>\u06cc\u06a9 \u0632\u0645\u06cc\u0646\u0647 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0628\u0631\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u06cc\u062c\u0627\u062f \u0645\u06cc \u0634\u0648\u062f <code>app.test_request_context<\/code>. \u0627\u06cc\u0646 \u0628\u0647 \u0622\u0632\u0645\u0648\u0646 \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc \u062f\u0647\u062f \u062a\u0627 \u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0631\u0627 \u0628\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0634\u0628\u06cc\u0647 \u0633\u0627\u0632\u06cc \u06a9\u0646\u062f.\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"k\">with<\/span> <span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"nf\">test_request_context<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">):<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0631\u0648\u0634 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0648 \u062f\u0627\u062f\u0647 \u0647\u0627\u06cc \u0641\u0631\u0645 \u0631\u0627 \u062a\u0646\u0638\u06cc\u0645 \u06a9\u0646\u06cc\u062f<\/strong><\/p>\n<p>\u0631\u0648\u0634 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0631\u0648\u06cc \u00abPOST\u00bb \u0648 \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0641\u0631\u0645 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0631\u0648\u06cc \u0641\u0631\u0647\u0646\u06af \u0644\u063a\u062a \u0628\u0627 \u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc \u00ab\u0645\u062d\u062a\u0648\u0627\u00bb \u0648 \u00ab\u062f\u0631\u062c\u0647\u00bb \u062a\u0646\u0638\u06cc\u0645 \u0645\u06cc\u200c\u0634\u0648\u062f.\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"n\">flask<\/span><span class=\"p\">.<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">method<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">POST<\/span><span class=\"sh\">'<\/span>\n<span class=\"n\">flask<\/span><span class=\"p\">.<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">form<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">content<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Test Content<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">degree<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Test Degree<\/span><span class=\"sh\">'<\/span><span class=\"p\">}<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a POST \u0628\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0631\u0633\u0627\u0644 \u06a9\u0646\u06cc\u062f<\/strong><\/p>\n<p>\u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a POST \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 \u0628\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc \u0634\u0648\u062f <code>self.app.post<\/code>. \u062f\u0627\u062f\u0647 \u0647\u0627\u06cc \u0641\u0631\u0645 \u0628\u0647 \u0639\u0646\u0648\u0627\u0646 \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc \u0634\u0648\u0646\u062f <code>data<\/code> \u0627\u0633\u062a\u062f\u0644\u0627\u0644\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"nf\">post<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">data<\/span><span class=\"o\">=<\/span><span class=\"n\">flask<\/span><span class=\"p\">.<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">form<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0646\u062a\u0627\u06cc\u062c \u0645\u0648\u0631\u062f \u0627\u0646\u062a\u0638\u0627\u0631 \u0631\u0627 \u062a\u0627\u06cc\u06cc\u062f \u06a9\u0646\u06cc\u062f<\/strong><\/p>\n<p>\u0627\u06cc\u0646 <code>assertEqual<\/code> \u0631\u0648\u0634 \u0628\u0631\u0627\u06cc \u0628\u0631\u0631\u0633\u06cc \u0627\u06cc\u0646\u06a9\u0647 \u06a9\u062f \u0648\u0636\u0639\u06cc\u062a \u067e\u0627\u0633\u062e 302 \u0627\u0633\u062a \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f <code>assert_called<\/code> \u0631\u0648\u0634\u06cc \u0628\u0631\u0627\u06cc \u0628\u0631\u0631\u0633\u06cc \u0627\u06cc\u0646\u06a9\u0647 <code>insert_one<\/code> \u0631\u0648\u0634 \u0646\u0627\u0645\u06cc\u062f\u0647 \u0634\u062f.\n<\/p>\n<pre class=\"highlight python\"><code><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"nf\">assertEqual<\/span><span class=\"p\">(<\/span><span class=\"n\">result<\/span><span class=\"p\">.<\/span><span class=\"n\">status_code<\/span><span class=\"p\">,<\/span> <span class=\"mi\">302<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">mock_insert_one<\/span><span class=\"p\">.<\/span><span class=\"nf\">assert_called<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>\u0627\u06cc\u0646 \u062a\u0633\u062a \u062a\u0636\u0645\u06cc\u0646 \u0645\u06cc \u06a9\u0646\u062f \u06a9\u0647 \u0648\u0642\u062a\u06cc \u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a POST \u0628\u0627 \u062f\u0627\u062f\u0647 \u0647\u0627\u06cc \u0641\u0631\u0645 \u0635\u062d\u06cc\u062d \u0628\u0647 \u0645\u0633\u06cc\u0631 \u0641\u0647\u0631\u0633\u062a \u0627\u0631\u0633\u0627\u0644 \u0645\u06cc \u0634\u0648\u062f\u060c \u0628\u0631\u0646\u0627\u0645\u0647 \u0628\u0627 \u06cc\u06a9 \u06a9\u062f \u0648\u0636\u0639\u06cc\u062a 302 \u067e\u0627\u0633\u062e \u0645\u06cc \u062f\u0647\u062f \u0648 \u062f\u0627\u062f\u0647 \u0647\u0627 \u0631\u0627 \u062f\u0631 \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0648\u0627\u0631\u062f \u0645\u06cc \u06a9\u0646\u062f.<\/p>\n<p>\u06a9\u062f \u062a\u0633\u062a \u0634\u0645\u0627 \u0628\u0627\u06cc\u062f \u0686\u06cc\u0632\u06cc \u0634\u0628\u06cc\u0647 \u0628\u0647 \u0632\u06cc\u0631 \u0628\u0627\u0634\u062f:\n<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">import<\/span> <span class=\"n\">unittest<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">unittest.mock<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">patch<\/span><span class=\"p\">,<\/span> <span class=\"n\">MagicMock<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">bson.objectid<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ObjectId<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">app<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">app<\/span><span class=\"p\">,<\/span> <span class=\"n\">todos<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">mongomock<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">flask<\/span>\n\n<span class=\"c1\">## Create a mock MongoDB instance\n<\/span><span class=\"n\">mock_db<\/span> <span class=\"o\">=<\/span> <span class=\"n\">mongomock<\/span><span class=\"p\">.<\/span><span class=\"nc\">MongoClient<\/span><span class=\"p\">().<\/span><span class=\"n\">db<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">TestApp<\/span><span class=\"p\">(<\/span><span class=\"n\">unittest<\/span><span class=\"p\">.<\/span><span class=\"n\">TestCase<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">setUp<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"c1\"># Create a test client instance\n<\/span>        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">app<\/span> <span class=\"o\">=<\/span> <span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"nf\">test_client<\/span><span class=\"p\">()<\/span>\n        <span class=\"c1\"># Enable testing mode. Exceptions are propagated rather than handled by the the app's error handlers\n<\/span>        <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"n\">testing<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">True<\/span> \n\n    <span class=\"k\">def<\/span> <span class=\"nf\">test_index_post<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"c1\"># Patch the insert_one method of todos with a MagicMock\n<\/span>        <span class=\"k\">with<\/span> <span class=\"nf\">patch<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">app.todos.insert_one<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">new_callable<\/span><span class=\"o\">=<\/span><span class=\"n\">MagicMock<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">mock_insert_one<\/span><span class=\"p\">:<\/span>\n            <span class=\"c1\"># Create a test request context for the app\n<\/span>            <span class=\"k\">with<\/span> <span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"nf\">test_request_context<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">):<\/span>\n                <span class=\"c1\"># Set the request method to 'POST'\n<\/span>                <span class=\"n\">flask<\/span><span class=\"p\">.<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">method<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">POST<\/span><span class=\"sh\">'<\/span>\n                <span class=\"c1\"># Set the request form data\n<\/span>                <span class=\"n\">flask<\/span><span class=\"p\">.<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">form<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"sh\">'<\/span><span class=\"s\">content<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Test Content<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">degree<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Test Degree<\/span><span class=\"sh\">'<\/span><span class=\"p\">}<\/span>\n                <span class=\"c1\"># Send a POST request to the app\n<\/span>                <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">app<\/span><span class=\"p\">.<\/span><span class=\"nf\">post<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">\/<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"n\">data<\/span><span class=\"o\">=<\/span><span class=\"n\">flask<\/span><span class=\"p\">.<\/span><span class=\"n\">request<\/span><span class=\"p\">.<\/span><span class=\"n\">form<\/span><span class=\"p\">)<\/span>\n                <span class=\"c1\"># Assert that the status code of the response is 302\n<\/span>                <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"nf\">assertEqual<\/span><span class=\"p\">(<\/span><span class=\"n\">result<\/span><span class=\"p\">.<\/span><span class=\"n\">status_code<\/span><span class=\"p\">,<\/span> <span class=\"mi\">302<\/span><span class=\"p\">)<\/span>\n                <span class=\"c1\"># Assert that the insert_one method was called\n<\/span>                <span class=\"n\">mock_insert_one<\/span><span class=\"p\">.<\/span><span class=\"nf\">assert_called<\/span><span class=\"p\">()<\/span>\n<\/code><\/pre>\n<\/div>\n<p>\u062d\u0627\u0644 \u0628\u0631\u0627\u06cc \u0627\u062c\u0631\u0627\u06cc \u062a\u0633\u062a\u060c \u0645\u062a\u063a\u06cc\u0631 \u0645\u062d\u06cc\u0637\u06cc TESTING=true\u060c Setting \u0631\u0627 \u062a\u0646\u0638\u06cc\u0645 \u06a9\u0646\u06cc\u062f <code>TESTING=True<\/code> \u0628\u0631\u0646\u0627\u0645\u0647 \u0631\u0627 \u062a\u063a\u06cc\u06cc\u0631 \u0645\u06cc \u062f\u0647\u062f \u062a\u0627 \u0628\u0647 \u062c\u0627\u06cc \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0648\u0627\u0642\u0639\u06cc MongoDB \u0627\u0632 \u06cc\u06a9 \u06a9\u0644\u0627\u06cc\u0646\u062a \u0633\u0627\u062e\u062a\u06af\u06cc MongoDB \u0628\u0631\u0627\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0646\u062f.<\/p>\n<p>\u062d\u0627\u0644\u060c \u0627\u06af\u0631 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0634\u0645\u0627 \u0645\u0648\u0641\u0642\u06cc\u062a \u0622\u0645\u06cc\u0632 \u0628\u0648\u062f\u060c \u0628\u06cc\u0627\u06cc\u06cc\u062f \u0628\u0647 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build \u0628\u0631\u0648\u06cc\u0645.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"%D8%B1%D8%A7%D9%87_%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C_Cloud_Build\"><\/span>\n<p>  \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc Cloud Build<br \/>\n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>\u0631\u0627\u0647\u0646\u0645\u0627\u06cc \u0627\u062a\u0635\u0627\u0644 Cloud Build \u0631\u0627 \u0628\u0647 \u0645\u062e\u0632\u0646 \u062e\u0648\u062f \u0648 \u0627\u06cc\u0646 \u06cc\u06a9\u06cc \u0628\u0631\u0627\u06cc \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0627\u0648\u0644\u06cc\u0647 \u062f\u0646\u0628\u0627\u0644 \u06a9\u0646\u06cc\u062f.<\/p>\n<p>\u067e\u0633 \u0627\u0632 \u0627\u0646\u062c\u0627\u0645 \u0627\u06cc\u0646 \u06a9\u0627\u0631\u060c \u0627\u062c\u0627\u0632\u0647 \u062f\u0647\u06cc\u062f \u0628\u0647 \u0646\u0648\u0634\u062a\u0646 \u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build \u0628\u0631\u0648\u06cc\u0645\u060c \u062c\u0627\u06cc\u06cc \u06a9\u0647 \u0628\u0647 \u0622\u0646 \u062f\u0631 \u0645\u0648\u0631\u062f \u0646\u062d\u0648\u0647 \u0627\u062c\u0631\u0627\u06cc \u062e\u0637 \u0644\u0648\u0644\u0647\u060c \u0645\u0631\u0627\u062d\u0644 \u0645\u0631\u0628\u0648\u0637\u0647\u060c \u0648\u0627\u0628\u0633\u062a\u06af\u06cc \u0647\u0627 \u0648 \u063a\u06cc\u0631\u0647 \u0622\u0645\u0648\u0632\u0634 \u0645\u06cc \u062f\u0647\u06cc\u0645.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"%D9%81%D8%A7%DB%8C%D9%84_%D9%BE%DB%8C%DA%A9%D8%B1%D8%A8%D9%86%D8%AF%DB%8C_Cloud_Build\"><\/span>\n<p>  \u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build<br \/>\n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>\u0641\u0627\u06cc\u0644 Cloud Build Config \u0628\u0647 \u0632\u0628\u0627\u0646 YAML \u0646\u0648\u0634\u062a\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a\u060c \u06cc\u06a9 \u0632\u0628\u0627\u0646 \u0633\u0631\u06cc\u0627\u0644\u200c\u0633\u0627\u0632\u06cc \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0642\u0627\u0628\u0644 \u062e\u0648\u0627\u0646\u062f\u0646 \u0628\u0631\u0627\u06cc \u0627\u0646\u0633\u0627\u0646.<\/p>\n<p>\u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u0628\u062e\u0634 \u0647\u0627\u06cc \u0627\u0635\u0644\u06cc \u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0645\u0627 \u0622\u0645\u062f\u0647 \u0627\u0633\u062a:<\/p>\n<ol>\n<li>\n<p><strong>\u062a\u0639\u0648\u06cc\u0636 \u0647\u0627<\/strong>: \u0627\u06cc\u0646\u0647\u0627 \u0645\u062a\u063a\u06cc\u0631\u0647\u0627\u06cc \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u062a\u0648\u0633\u0637 \u06a9\u0627\u0631\u0628\u0631 \u0647\u0633\u062a\u0646\u062f \u06a9\u0647 \u0645\u06cc \u062a\u0648\u0627\u0646\u0646\u062f \u062f\u0631 \u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Cloud Build \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646 \u0634\u0648\u0646\u062f. \u0622\u0646\u0647\u0627 \u062a\u062d\u062a \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0646\u062f <code>substitutions<\/code> \u06a9\u0644\u06cc\u062f \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0648\u0631\u062f\u060c <code>_REGION<\/code>\u060c <code>_REPOSITORY<\/code>\u060c <code>_IMAGE<\/code>\u060c \u0648 <code>_SEVERITY<\/code> \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0646\u062f.\n<\/p>\n<pre class=\"highlight yaml\"><code><span class=\"na\">substitutions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">_REGION<\/span><span class=\"pi\">:<\/span> <span class=\"s\">us-central1<\/span>\n  <span class=\"na\">_REPOSITORY<\/span><span class=\"pi\">:<\/span> <span class=\"s\">from-legacy-to-cloud<\/span>\n  <span class=\"na\">_IMAGE<\/span><span class=\"pi\">:<\/span> <span class=\"s\">from-legacy-to-cloud<\/span>\n  <span class=\"na\">_SEVERITY<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">\"CRITICAL|HIGH\"'<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0645\u0631\u0627\u062d\u0644<\/strong>: \u0627\u06cc\u0646\u0647\u0627 \u0639\u0645\u0644\u06cc\u0627\u062a\u06cc \u0647\u0633\u062a\u0646\u062f \u06a9\u0647 Cloud Build \u0627\u0646\u062c\u0627\u0645 \u062e\u0648\u0627\u0647\u062f \u062f\u0627\u062f. \u0647\u0631 \u0645\u0631\u062d\u0644\u0647 \u06cc\u06a9 \u0639\u0645\u0644 \u062c\u062f\u0627\u06af\u0627\u0646\u0647 \u0627\u0633\u062a \u0648 \u0628\u0647 \u062a\u0631\u062a\u06cc\u0628\u06cc \u06a9\u0647 \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0646\u062f \u0627\u062c\u0631\u0627 \u0645\u06cc \u0634\u0648\u0646\u062f.<\/p>\n<\/li>\n<\/ol>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>* **Step 0: Install test dependencies**: This step uses a Python 3.10 Docker image to install the test dependencies listed in `docker\/requirements-test.txt`. The `entrypoint` is set to `\/bin\/bash`, which means that the command that follows will be executed in a bash shell. The `args` key specifies the command to be executed, which in this case is a pip install command. The `-c` flag tells bash to read commands from the following string. The `|` character allows us to write multiple commands, which will be executed in order.\n<\/code><\/pre>\n<\/div>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>    ```yaml\n    - name: 'python:3.10-slim'\n      entrypoint: '\/bin\/bash'\n      args:\n        - '-c'\n        - |\n          pip install --user -r docker\/requirements-test.txt\n      id: 'install-test-dependencies'\n    ```\n<\/code><\/pre>\n<\/div>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>* **Step 1: Run unit tests**: This step also uses a Python 3.10 Docker image to run the unit tests defined in [`test.py`](http:\/\/test.py). The `export TESTING=True` command sets an environment variable `TESTING` to `True`, which can be used to change the behavior of the application during testing. The `cd docker` command changes the current directory to `docker`, where the test file is located. The `python -m unittest` [`test.py`](http:\/\/test.py) command runs the unit tests in [`test.py`](http:\/\/test.py).\n<\/code><\/pre>\n<\/div>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>    ```yaml\n    - name: 'python:3.10-slim'\n      entrypoint: '\/bin\/bash'\n      args:\n        - '-c'\n        - |\n          export TESTING=True\n          cd docker \n          python -m unittest test.py\n      id: 'run-tests'\n    ```\n<\/code><\/pre>\n<\/div>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>* **Step 2: Build the Docker image**: This step uses the `docker` Cloud Builder to build a Docker image from the Dockerfile located in the `docker\/` directory. The image is tagged with the commit SHA. The `waitFor` key is used to specify that this step should wait for the `run-tests` step to complete before it starts. The `args` key specifies the command to be executed, which in this case is a docker build command. The `-t` flag is used to name and optionally tag the image in the 'name:tag' format.\n<\/code><\/pre>\n<\/div>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>    ```yaml\n    - name: 'gcr.io\/cloud-builders\/docker'\n      args: ['build', '-t', '$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA', 'docker\/']\n      waitFor: ['run-tests']\n      id: 'build-image'\n    ```\n<\/code><\/pre>\n<\/div>\n<ul>\n<li>\n<p><strong>\u0645\u0631\u062d\u0644\u0647 3: \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f \u0648 \u062e\u0644\u0627\u0635\u0647 \u0631\u0627 \u062f\u0631 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0628\u0646\u0648\u06cc\u0633\u06cc\u062f<\/strong>: \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0627\u0632 <code>docker<\/code> Cloud Builder \u0628\u0631\u0627\u06cc \u0628\u0631\u0631\u0633\u06cc \u062a\u0635\u0648\u06cc\u0631 Docker \u0648 \u0646\u0648\u0634\u062a\u0646 \u062e\u0644\u0627\u0635\u0647 \u062a\u0635\u0648\u06cc\u0631 \u062f\u0631 \u06cc\u06a9 \u0641\u0627\u06cc\u0644. \u062e\u0644\u0627\u0635\u0647 \u062a\u0635\u0648\u06cc\u0631 \u06cc\u06a9 \u0634\u0646\u0627\u0633\u0647 \u0645\u0646\u062d\u0635\u0631 \u0628\u0647 \u0641\u0631\u062f \u0628\u0631\u0627\u06cc \u062a\u0635\u0648\u06cc\u0631 \u0627\u0633\u062a. \u0627\u06cc\u0646 <code>docker image inspect<\/code> \u062f\u0633\u062a\u0648\u0631 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u062f\u0642\u06cc\u0642 \u062f\u0631 \u0645\u0648\u0631\u062f \u062a\u0635\u0648\u06cc\u0631 \u062f\u0627\u06a9\u0631 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0645\u06cc \u06a9\u0646\u062f. \u0627\u06cc\u0646 <code>--format<\/code> \u06af\u0632\u06cc\u0646\u0647 \u0628\u0631\u0627\u06cc \u0642\u0627\u0644\u0628 \u0628\u0646\u062f\u06cc \u062e\u0631\u0648\u062c\u06cc \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0627\u0644\u06af\u0648\u0647\u0627\u06cc Go \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 <code>{{index .RepoTags 0}}@{{.Id}}<\/code> \u0627\u0644\u06af\u0648 \u0627\u0648\u0644\u06cc\u0646 \u062a\u06af \u062a\u0635\u0648\u06cc\u0631 \u0648 \u0634\u0646\u0627\u0633\u0647 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0645\u06cc \u06a9\u0646\u062f. \u0627\u06cc\u0646 <code>&gt;<\/code> \u0627\u067e\u0631\u0627\u062a\u0648\u0631 \u062e\u0631\u0648\u062c\u06cc \u0631\u0627 \u0628\u0647 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0647\u062f\u0627\u06cc\u062a \u0645\u06cc \u06a9\u0646\u062f. \u0627\u06cc\u0646 <code>&amp;&amp;<\/code> \u0627\u0632 \u0639\u0645\u0644\u06af\u0631 \u0628\u0631\u0627\u06cc \u0627\u062c\u0631\u0627\u06cc <code>cat<\/code> \u0641\u0642\u0637 \u062f\u0631 \u0635\u0648\u0631\u062a\u06cc \u062f\u0633\u062a\u0648\u0631 \u062f\u0647\u06cc\u062f \u06a9\u0647 \u062f\u0633\u062a\u0648\u0631 \u0642\u0628\u0644\u06cc \u0645\u0648\u0641\u0642\u06cc\u062a \u0622\u0645\u06cc\u0632 \u0628\u0627\u0634\u062f.\n<\/p>\n<pre class=\"highlight yaml\"><code><span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">gcr.io\/cloud-builders\/docker'<\/span>\n  <span class=\"na\">entrypoint<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">\/bin\/bash'<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span>\n    <span class=\"pi\">-<\/span> <span class=\"s1\">'<\/span><span class=\"s\">-c'<\/span>\n    <span class=\"pi\">-<\/span> <span class=\"pi\">|<\/span>\n      <span class=\"s\">docker image inspect $_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA --format '{{index .RepoTags 0}}@{{.Id}}' &gt; \/workspace\/image-digest.txt &amp;&amp;<\/span>\n      <span class=\"s\">cat \/workspace\/image-digest.txt<\/span>\n  <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">inspect-image'<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0645\u0631\u062d\u0644\u0647 4: \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0631\u0627\u06cc \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u0627\u0633\u06a9\u0646 \u06a9\u0646\u06cc\u062f<\/strong>: \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0627\u0632 <code>cloud-sdk<\/code> Cloud Builder \u0628\u0631\u0627\u06cc \u0627\u0633\u06a9\u0646 \u062a\u0635\u0648\u06cc\u0631 Docker \u0628\u0631\u0627\u06cc \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc\u200c\u0647\u0627. \u0634\u0646\u0627\u0633\u0647 \u0627\u0633\u06a9\u0646 \u062f\u0631 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0646\u0648\u0634\u062a\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 <code>gcloud artifacts docker images scan<\/code> \u062f\u0633\u062a\u0648\u0631 \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0631\u0627\u06cc \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u0627\u0633\u06a9\u0646 \u0645\u06cc\u200c\u06a9\u0646\u062f. \u0627\u06cc\u0646 <code>--format=\"value(response.scan)\"<\/code> \u06af\u0632\u06cc\u0646\u0647 \u0628\u0631\u0627\u06cc \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0634\u0646\u0627\u0633\u0647 \u0627\u0633\u06a9\u0646 \u0627\u0632 \u067e\u0627\u0633\u062e \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 <code>&gt;<\/code> \u0627\u067e\u0631\u0627\u062a\u0648\u0631 \u062e\u0631\u0648\u062c\u06cc \u0631\u0627 \u0628\u0647 \u06cc\u06a9 \u0641\u0627\u06cc\u0644 \u0647\u062f\u0627\u06cc\u062a \u0645\u06cc \u06a9\u0646\u062f.\n<\/p>\n<pre class=\"highlight yaml\"><code><span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s\">scan<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gcr.io\/google.com\/cloudsdktool\/cloud-sdk<\/span>\n  <span class=\"na\">entrypoint<\/span><span class=\"pi\">:<\/span> <span class=\"s\">\/bin\/bash<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"s\">-c<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"pi\">|<\/span>\n    <span class=\"s\">gcloud artifacts docker images scan $_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA \\<\/span>\n    <span class=\"s\">--format=\"value(response.scan)\" &gt; \/workspace\/scan_id.txt<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0645\u0631\u062d\u0644\u0647 5: \u0634\u062f\u062a \u0647\u0631 \u06af\u0648\u0646\u0647 \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u06cc\u0627\u0641\u062a \u0634\u062f\u0647 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f<\/strong>: \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0627\u0632 <code>cloud-sdk<\/code> Cloud Builder \u0628\u0631\u0627\u06cc \u0641\u0647\u0631\u0633\u062a \u06a9\u0631\u062f\u0646 \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc\u200c\u0647\u0627\u06cc \u0645\u0648\u062c\u0648\u062f \u062f\u0631 \u062a\u0635\u0648\u06cc\u0631 Docker \u0648 \u0628\u0631\u0631\u0633\u06cc \u0634\u062f\u062a \u0622\u0646\u0647\u0627. \u062f\u0631 \u0635\u0648\u0631\u062a \u0648\u062c\u0648\u062f \u0647\u0631 \u06af\u0648\u0646\u0647 \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u0628\u0627 \u062a\u0637\u0627\u0628\u0642 \u0634\u062f\u062a <code>_SEVERITY<\/code> \u067e\u06cc\u062f\u0627 \u0645\u06cc \u0634\u0648\u0646\u062f\u060c \u0633\u0627\u062e\u062a \u0628\u0627 \u0634\u06a9\u0633\u062a \u0645\u0648\u0627\u062c\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 <code>gcloud artifacts docker images list-vulnerabilities<\/code> \u062f\u0633\u062a\u0648\u0631\u060c \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u0647\u0627\u06cc \u0645\u0648\u062c\u0648\u062f \u062f\u0631 \u062a\u0635\u0648\u06cc\u0631 \u062f\u0627\u06a9\u0631 \u0631\u0627 \u0641\u0647\u0631\u0633\u062a \u0645\u06cc \u06a9\u0646\u062f. \u0627\u06cc\u0646 <code>--format=\"value(vulnerability.effectiveSeverity)\"<\/code> \u06af\u0632\u06cc\u0646\u0647 \u0628\u0631\u0627\u06cc \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0634\u062f\u062a \u0647\u0631 \u0622\u0633\u06cc\u0628 \u067e\u0630\u06cc\u0631\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f. \u0627\u06cc\u0646 <code>grep -Exq $_SEVERITY<\/code> \u062f\u0633\u062a\u0648\u0631 \u0628\u0631\u0631\u0633\u06cc \u0645\u06cc \u06a9\u0646\u062f \u06a9\u0647 \u0622\u06cc\u0627 \u0647\u0631 \u06cc\u06a9 \u0627\u0632 \u0634\u062f\u062a \u0647\u0627 \u0645\u0637\u0627\u0628\u0642\u062a \u062f\u0627\u0631\u0646\u062f \u06cc\u0627 \u062e\u06cc\u0631 <code>_SEVERITY<\/code>. \u0627\u06cc\u0646 <code>echo<\/code> \u062f\u0633\u062a\u0648\u0631 \u06cc\u06a9 \u067e\u06cc\u0627\u0645 \u0631\u0627 \u0686\u0627\u067e \u0645\u06cc \u06a9\u0646\u062f \u0648 <code>exit 1<\/code> \u0627\u06af\u0631 \u0645\u0637\u0627\u0628\u0642\u062a \u067e\u06cc\u062f\u0627 \u0634\u0648\u062f\u060c \u062f\u0633\u062a\u0648\u0631 \u0633\u0627\u062e\u062a \u0631\u0627 \u062e\u0627\u062a\u0645\u0647 \u0645\u06cc \u062f\u0647\u062f.\n<\/p>\n<pre class=\"highlight yaml\"><code><span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s\">severity check<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gcr.io\/google.com\/cloudsdktool\/cloud-sdk<\/span>\n  <span class=\"na\">entrypoint<\/span><span class=\"pi\">:<\/span> <span class=\"s\">\/bin\/bash<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"s\">-c<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"pi\">|<\/span>\n    <span class=\"s\">gcloud artifacts docker images list-vulnerabilities $(cat \/workspace\/scan_id.txt) \\<\/span>\n    <span class=\"s\">--format=\"value(vulnerability.effectiveSeverity)\" | if grep -Exq $_SEVERITY; \\<\/span>\n    <span class=\"s\">then echo 'Failed vulnerability check' &amp;&amp; exit 1; else exit 0; fi<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u0645\u0631\u062d\u0644\u0647 6: \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0647 Google Cloud Artifact Registry \u0641\u0634\u0627\u0631 \u062f\u0647\u06cc\u062f<\/strong>: \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0627\u0632 <code>docker<\/code> Cloud Builder \u0628\u0631\u0627\u06cc \u0641\u0634\u0627\u0631 \u062f\u0627\u062f\u0646 \u062a\u0635\u0648\u06cc\u0631 Docker \u0628\u0647 Google Cloud Artifact Registry. \u0627\u06cc\u0646 <code>waitFor<\/code> \u0627\u0632 \u06a9\u0644\u06cc\u062f \u0628\u0631\u0627\u06cc \u062a\u0639\u06cc\u06cc\u0646 \u0627\u06cc\u0646\u06a9\u0647 \u0627\u06cc\u0646 \u0645\u0631\u062d\u0644\u0647 \u0628\u0627\u06cc\u062f \u0645\u0646\u062a\u0638\u0631 \u0628\u0645\u0627\u0646\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u0634\u0648\u062f <code>severity check<\/code> \u0645\u0631\u062d\u0644\u0647 \u0628\u0631\u0627\u06cc \u062a\u06a9\u0645\u06cc\u0644 \u0642\u0628\u0644 \u0627\u0632 \u0634\u0631\u0648\u0639. \u0627\u06cc\u0646 <code>docker push<\/code> \u062f\u0633\u062a\u0648\u0631 \u062a\u0635\u0648\u06cc\u0631 Docker \u0631\u0627 \u0628\u0647 \u06cc\u06a9 \u0645\u062e\u0632\u0646 \u0647\u0644 \u0645\u06cc \u062f\u0647\u062f.\n<\/p>\n<pre class=\"highlight yaml\"><code><span class=\"pi\">-<\/span> <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">gcr.io\/cloud-builders\/docker'<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s1\">'<\/span><span class=\"s\">push'<\/span><span class=\"pi\">,<\/span> <span class=\"s1\">'<\/span><span class=\"s\">$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA'<\/span><span class=\"pi\">]<\/span>\n  <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">push-image'<\/span>\n  <span class=\"na\">waitFor<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s1\">'<\/span><span class=\"s\">severity<\/span><span class=\"nv\"> <\/span><span class=\"s\">check'<\/span><span class=\"pi\">]<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>\u062a\u0635\u0627\u0648\u06cc\u0631<\/strong>: \u0627\u06cc\u0646 \u06a9\u0644\u06cc\u062f \u062a\u0635\u0627\u0648\u06cc\u0631 Docker \u0631\u0627 \u06a9\u0647 Cloud Build \u0628\u0627\u06cc\u062f \u0628\u0633\u0627\u0632\u062f \u0648 \u0628\u0647 \u0631\u062c\u06cc\u0633\u062a\u0631\u06cc Google Cloud Artifact \u0641\u0634\u0627\u0631 \u062f\u0647\u062f\u060c \u0645\u0634\u062e\u0635 \u0645\u06cc \u06a9\u0646\u062f. \u062f\u0631 \u0627\u06cc\u0646 \u0645\u0648\u0631\u062f\u060c \u062a\u0635\u0648\u06cc\u0631 Docker \u0633\u0627\u062e\u062a\u0647 \u0634\u062f\u0647 \u062f\u0631 \u0645\u0631\u062d\u0644\u0647 2 \u0627\u0633\u062a.\n<\/p>\n<pre class=\"highlight yaml\"><code><span class=\"na\">images<\/span><span class=\"pi\">:<\/span>\n<span class=\"pi\">-<\/span> <span class=\"s1\">'<\/span><span class=\"s\">$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA'<\/span>\n<\/code><\/pre>\n<\/li>\n<\/ul>\n<p>\u0627\u06cc\u0646 <code>cloudbuild.yaml<\/code> \u0641\u0627\u06cc\u0644 \u06cc\u06a9 \u062e\u0637 \u0644\u0648\u0644\u0647 \u06a9\u0627\u0645\u0644 CI\/CD \u0631\u0627 \u0628\u0631\u0627\u06cc \u0628\u0631\u0646\u0627\u0645\u0647 \u0645\u0627 \u062a\u0639\u0631\u06cc\u0641 \u0645\u06cc \u06a9\u0646\u062f. \u0648\u0627\u0628\u0633\u062a\u06af\u06cc\u200c\u0647\u0627\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u0631\u0627 \u0646\u0635\u0628 \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0622\u0632\u0645\u0627\u06cc\u0634\u200c\u0647\u0627\u06cc \u0648\u0627\u062d\u062f \u0631\u0627 \u0627\u062c\u0631\u0627 \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u06cc\u06a9 \u062a\u0635\u0648\u06cc\u0631 Docker \u0645\u06cc\u200c\u0633\u0627\u0632\u062f\u060c \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0628\u0627\u0632\u0631\u0633\u06cc \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u0627\u0633\u06a9\u0646 \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0634\u062f\u062a \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc\u200c\u0647\u0627\u06cc \u06cc\u0627\u0641\u062a \u0634\u062f\u0647 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u0645\u06cc\u200c\u06a9\u0646\u062f \u0648 \u062a\u0635\u0648\u06cc\u0631 \u0631\u0627 \u0628\u0647 \u0631\u062c\u06cc\u0633\u062a\u0631\u06cc Google Cloud Artifact \u0645\u0646\u062a\u0642\u0644 \u0645\u06cc\u200c\u06a9\u0646\u062f. \u0627\u06cc\u0646 \u062e\u0637 \u0644\u0648\u0644\u0647 \u062a\u0636\u0645\u06cc\u0646 \u0645\u06cc \u06a9\u0646\u062f \u06a9\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0634\u062f\u0647\u060c \u0627\u06cc\u0645\u0646 \u0648 \u0622\u0645\u0627\u062f\u0647 \u0627\u0633\u062a\u0642\u0631\u0627\u0631 \u0627\u0633\u062a.<\/p>\n<p>\u0641\u0627\u06cc\u0644 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u06a9\u0627\u0645\u0644 \u0628\u0627\u06cc\u062f \u0628\u0647 \u0634\u06a9\u0644 \u0632\u06cc\u0631 \u0628\u0627\u0634\u062f:\n<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight yaml\"><code><span class=\"na\">substitutions<\/span><span class=\"pi\">:<\/span>\n  <span class=\"na\">_REGION<\/span><span class=\"pi\">:<\/span> <span class=\"s\">us-central1<\/span>\n  <span class=\"na\">_REPOSITORY<\/span><span class=\"pi\">:<\/span> <span class=\"s\">from-legacy-to-cloud<\/span>\n  <span class=\"na\">_IMAGE<\/span><span class=\"pi\">:<\/span> <span class=\"s\">from-legacy-to-cloud<\/span>\n  <span class=\"na\">_SEVERITY<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">\"CRITICAL|HIGH\"'<\/span>\n\n<span class=\"na\">steps<\/span><span class=\"pi\">:<\/span>\n<span class=\"c1\"># Step 0: Install test dependencies<\/span>\n<span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">install-test-dependencies'<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">python:3.10-slim'<\/span>\n  <span class=\"na\">entrypoint<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">\/bin\/bash'<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span>\n    <span class=\"pi\">-<\/span> <span class=\"s1\">'<\/span><span class=\"s\">-c'<\/span>\n    <span class=\"pi\">-<\/span> <span class=\"pi\">|<\/span>\n      <span class=\"s\">pip install --user -r docker\/requirements-test.txt<\/span>\n\n<span class=\"c1\"># Step 1: Run unit tests<\/span>\n<span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">run-tests'<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">python:3.10-slim'<\/span>\n  <span class=\"na\">entrypoint<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">\/bin\/bash'<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span>\n    <span class=\"pi\">-<\/span> <span class=\"s1\">'<\/span><span class=\"s\">-c'<\/span>\n    <span class=\"pi\">-<\/span> <span class=\"pi\">|<\/span>\n      <span class=\"s\">export TESTING=True<\/span>\n      <span class=\"s\">cd docker <\/span>\n      <span class=\"s\">python -m unittest test.py<\/span>\n\n<span class=\"c1\"># Step 2: Build the Docker image<\/span>\n<span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">build-image'<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">gcr.io\/cloud-builders\/docker'<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s1\">'<\/span><span class=\"s\">build'<\/span><span class=\"pi\">,<\/span> <span class=\"s1\">'<\/span><span class=\"s\">-t'<\/span><span class=\"pi\">,<\/span> <span class=\"s1\">'<\/span><span class=\"s\">$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA'<\/span><span class=\"pi\">,<\/span> <span class=\"s1\">'<\/span><span class=\"s\">docker\/'<\/span><span class=\"pi\">]<\/span>\n  <span class=\"na\">waitFor<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s1\">'<\/span><span class=\"s\">run-tests'<\/span><span class=\"pi\">]<\/span>\n\n<span class=\"c1\"># Step 3: Inspect the Docker image and write the digest to a file.<\/span>\n<span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">inspect-image'<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">gcr.io\/cloud-builders\/docker'<\/span>\n  <span class=\"na\">entrypoint<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">\/bin\/bash'<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span>\n    <span class=\"pi\">-<\/span> <span class=\"s1\">'<\/span><span class=\"s\">-c'<\/span>\n    <span class=\"pi\">-<\/span> <span class=\"pi\">|<\/span>\n      <span class=\"s\">docker image inspect $_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA --format '{{index .RepoTags 0}}@{{.Id}}' &gt; \/workspace\/image-digest.txt &amp;&amp;<\/span>\n      <span class=\"s\">cat \/workspace\/image-digest.txt<\/span>\n\n<span class=\"c1\"># Step 4: Scan the Docker image for vulnerabilities<\/span>\n<span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s\">scan<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gcr.io\/google.com\/cloudsdktool\/cloud-sdk<\/span>\n  <span class=\"na\">entrypoint<\/span><span class=\"pi\">:<\/span> <span class=\"s\">\/bin\/bash<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"s\">-c<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"pi\">|<\/span>\n    <span class=\"s\">gcloud artifacts docker images scan $_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA \\<\/span>\n    <span class=\"s\">--format=\"value(response.scan)\" &gt; \/workspace\/scan_id.txt<\/span>\n\n<span class=\"c1\"># Step 5: Check the severity of any vulnerabilities found<\/span>\n<span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s\">severity check<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s\">gcr.io\/google.com\/cloudsdktool\/cloud-sdk<\/span>\n  <span class=\"na\">entrypoint<\/span><span class=\"pi\">:<\/span> <span class=\"s\">\/bin\/bash<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"s\">-c<\/span>\n  <span class=\"pi\">-<\/span> <span class=\"pi\">|<\/span>\n    <span class=\"s\">gcloud artifacts docker images list-vulnerabilities $(cat \/workspace\/scan_id.txt) \\<\/span>\n    <span class=\"s\">--format=\"value(vulnerability.effectiveSeverity)\" | if grep -Exq $_SEVERITY; \\<\/span>\n    <span class=\"s\">then echo 'Failed vulnerability check' &amp;&amp; exit 1; else exit 0; fi<\/span>\n\n<span class=\"c1\"># Step 6: Push the Docker image to Google Cloud Artifact Registry<\/span>\n<span class=\"pi\">-<\/span> <span class=\"na\">id<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">push-image'<\/span>\n  <span class=\"na\">name<\/span><span class=\"pi\">:<\/span> <span class=\"s1\">'<\/span><span class=\"s\">gcr.io\/cloud-builders\/docker'<\/span>\n  <span class=\"na\">args<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s1\">'<\/span><span class=\"s\">push'<\/span><span class=\"pi\">,<\/span> <span class=\"s1\">'<\/span><span class=\"s\">$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA'<\/span><span class=\"pi\">]<\/span>\n  <span class=\"na\">waitFor<\/span><span class=\"pi\">:<\/span> <span class=\"pi\">[<\/span><span class=\"s1\">'<\/span><span class=\"s\">severity<\/span><span class=\"nv\"> <\/span><span class=\"s\">check'<\/span><span class=\"pi\">]<\/span>\n\n<span class=\"na\">images<\/span><span class=\"pi\">:<\/span>\n<span class=\"pi\">-<\/span> <span class=\"s1\">'<\/span><span class=\"s\">$_REGION-docker.pkg.dev\/$PROJECT_ID\/$_REPOSITORY\/$_IMAGE:$COMMIT_SHA'<\/span>\n<\/code><\/pre>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"%D9%85%D8%B4%D8%A7%D9%87%D8%AF%D9%87_%D9%86%D8%AA%D8%A7%DB%8C%D8%AC_%D8%B3%D8%A7%D8%AE%D8%AA\"><\/span>\n<p>  \u0645\u0634\u0627\u0647\u062f\u0647 \u0646\u062a\u0627\u06cc\u062c \u0633\u0627\u062e\u062a<br \/>\n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>\u0627\u06a9\u0646\u0648\u0646\u060c \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u062e\u0648\u062f \u0631\u0627 \u0645\u062a\u0639\u0647\u062f \u0648 \u0641\u0634\u0627\u0631 \u062f\u0647\u06cc\u062f. \u0627\u06af\u0631 \u0645\u062d\u0631\u06a9 \u0647\u0627\u06cc \u0633\u0627\u062e\u062a \u0627\u0628\u0631 \u0628\u0647 \u062f\u0631\u0633\u062a\u06cc \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0634\u062f\u0647 \u0628\u0627\u0634\u0646\u062f\u060c \u0633\u0627\u062e\u062a \u0628\u0627\u06cc\u062f \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc \u0634\u0648\u062f. \u0628\u0647 Google Cloud Console \u0645\u062a\u0635\u0644 \u0634\u0648\u06cc\u062f\u060c \u0628\u0631\u0627\u06cc \u0645\u0634\u0627\u0647\u062f\u0647 \u0633\u0627\u062e\u062a\u200c\u0647\u0627\u06cc \u062e\u0648\u062f \u0628\u0647 Cloud Build > History \u0628\u0631\u0648\u06cc\u062f.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/media.dev.to\/cdn-cgi\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83qyrfx5veukvw7txr3k.png\" alt=\"\u0646\u062a\u06cc\u062c\u0647 \u0633\u0627\u062e\u062a\" width=\"800\" height=\"482\" title=\"\"><\/p>\n<p>\u062f\u0631 \u0635\u0648\u0631\u062a \u0639\u062f\u0645 \u0645\u0648\u0641\u0642\u06cc\u062a\u060c \u0631\u0648\u06cc \u0622\u0646 \u06a9\u0644\u06cc\u06a9 \u06a9\u0646\u06cc\u062f \u062a\u0627 \u067e\u06cc\u0627\u0645 \u0647\u0627\u06cc \u062e\u0637\u0627 \u0631\u0627 \u0628\u0628\u06cc\u0646\u06cc\u062f \u0648 \u0628\u0631\u0627\u06cc \u0631\u0641\u0639 \u0645\u0634\u06a9\u0644\u0627\u062a \u0639\u06cc\u0628 \u06cc\u0627\u0628\u06cc \u06a9\u0646\u06cc\u062f. \u067e\u0633 \u0627\u0632 \u0645\u0648\u0641\u0642\u06cc\u062a \u062f\u0631 \u0633\u0627\u062e\u062a\u060c \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u0628\u0647 \u0631\u062c\u06cc\u0633\u062a\u0631\u06cc Artifact \u062f\u0633\u062a\u0631\u0633\u06cc \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f \u0648 \u062a\u0635\u0648\u06cc\u0631 \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0631\u0627 \u0628\u0631\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u0634\u0627\u0647\u062f\u0647 \u06a9\u0646\u06cc\u062f.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/media.dev.to\/cdn-cgi\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lieu8f0ho1nsvd8z576.png\" alt=\"\u0646\u062a\u06cc\u062c\u0647 \u0633\u0627\u062e\u062a\" width=\"800\" height=\"435\" title=\"\"><\/p>\n<h2><span class=\"ez-toc-section\" id=\"%D8%A8%D8%B9%D8%AF%D8%B4_%DA%86%DB%8C%D8%9F\"><\/span>\n<p>  \u0628\u0639\u062f\u0634 \u0686\u06cc\u061f<br \/>\n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>\u062e\u0648\u0628\u060c \u0627\u06cc\u0646 \u0645\u0642\u0627\u0644\u0647 \u0631\u0627 \u0628\u0647 \u067e\u0627\u06cc\u0627\u0646 \u0645\u06cc \u0631\u0633\u0627\u0646\u062f. \u062f\u0631 \u0642\u0633\u0645\u062a \u0628\u0639\u062f\u06cc\u060c \u0645\u0627 \u0628\u0647 \u0627\u0633\u062a\u0642\u0631\u0627\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 &#8211; \u0628\u062e\u0634 CD &#8211; \u062e\u0648\u0627\u0647\u06cc\u0645 \u067e\u0631\u062f\u0627\u062e\u062a. \u067e\u0633 \u0627\u0632 \u0627\u0633\u06a9\u0646 \u0622\u0633\u06cc\u0628\u200c\u067e\u0630\u06cc\u0631\u06cc \u062a\u0635\u0627\u0648\u06cc\u0631 \u06a9\u0627\u0646\u062a\u06cc\u0646\u0631\u060c \u0645\u0627 \u0633\u06cc\u0627\u0633\u062a\u200c\u0647\u0627\u06cc \u0627\u0645\u0646\u06cc\u062a\u06cc \u0631\u0627 \u0627\u0632 \u0637\u0631\u06cc\u0642 \u0645\u062c\u0648\u0632 \u0628\u0627\u06cc\u0646\u0631\u06cc \u0627\u0639\u0645\u0627\u0644 \u0645\u06cc\u200c\u06a9\u0646\u06cc\u0645 \u06a9\u0647 \u0627\u062c\u0627\u0632\u0647 \u0645\u06cc\u200c\u062f\u0647\u062f \u0641\u0642\u0637 \u062a\u0635\u0627\u0648\u06cc\u0631 \u062a\u0623\u06cc\u06cc\u062f \u0634\u062f\u0647\/\u0645\u0639\u062a\u0645\u062f \u062f\u0631 Cloud Run \u0645\u0633\u062a\u0642\u0631 \u0634\u0648\u0646\u062f. \u0627\u0645\u0627 \u0642\u0628\u0644 \u0627\u0632 \u0622\u0646\u060c \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 Mongo \u062e\u0648\u062f \u0631\u0627 \u0628\u0647 Google Firestore \u0645\u0646\u062a\u0642\u0644 \u0645\u06cc \u06a9\u0646\u06cc\u0645. \u067e\u0633 \u0627\u0632 \u0622\u0646\u060c \u0645\u0627 \u0628\u0631\u0646\u0627\u0645\u0647 \u062e\u0648\u062f \u0631\u0627 \u062f\u0631 Cloud Run \u0645\u0633\u062a\u0642\u0631 \u0645\u06cc \u06a9\u0646\u06cc\u0645 \u0648 \u0622\u0646 \u0631\u0627 \u0628\u0647 Firestore \u0645\u062a\u0635\u0644 \u0645\u06cc \u06a9\u0646\u06cc\u0645 \u062a\u0627 \u06a9\u0627\u0645\u0644\u0627\u064b \u0639\u0645\u0644\u06cc\u0627\u062a\u06cc \u0634\u0648\u062f.<\/p>\n<p>\u0634\u0645\u0627 \u0631\u0627 \u062f\u0631 \u0645\u0642\u0627\u0644\u0647 \u0628\u0639\u062f\u06cc \u0645\u06cc \u0628\u06cc\u0646\u06cc\u0645. \u062a\u0627 \u0622\u0646 \u0632\u0645\u0627\u0646\u060c \u0645\u0646 \u062f\u0631 \u0634\u0628\u06a9\u0647 \u0647\u0627\u06cc \u0627\u062c\u062a\u0645\u0627\u0639\u06cc (\u0645\u0646 \u062f\u0631 \u0644\u06cc\u0646\u06a9\u062f\u06cc\u0646 \u0641\u0639\u0627\u0644 \u062a\u0631 \u0647\u0633\u062a\u0645) \u0628\u0631\u0627\u06cc \u0647\u0631\u06af\u0648\u0646\u0647 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u06cc\u0627 \u067e\u06cc\u0634\u0646\u0647\u0627\u062f \u0627\u0636\u0627\u0641\u06cc \u062f\u0631 \u062f\u0633\u062a\u0631\u0633 \u0647\u0633\u062a\u0645. \u0628\u0627 \u062a\u0634\u06a9\u0631 \u0628\u0631\u0627\u06cc \u062e\u0648\u0627\u0646\u062f\u0646!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summarize this content to 400 words in Persian Lang \u062a\u0648\u062c\u0647: \u0627\u06cc\u0646 \u0645\u0642\u0627\u0644\u0647 \u062f\u0631 \u0627\u0628\u062a\u062f\u0627 \u062f\u0631 \u062a\u0627\u0631\u06cc\u062e \u0645\u0646\u062a\u0634\u0631 \u0634\u062f\u0647 \u0627\u0633\u062a 25 \u062f\u0633\u0627\u0645\u0628\u0631 2023 \u0627\u06cc\u0646\u062c\u0627. \u0628\u0631\u0627\u06cc \u062f\u0633\u062a\u06cc\u0627\u0628\u06cc \u0628\u0647 \u0645\u062e\u0627\u0637\u0628\u0627\u0646 \u0628\u06cc\u0634\u062a\u0631 \u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u0628\u0627\u0632\u0646\u0634\u0631 \u0634\u062f\u0647 \u0627\u0633\u062a. \u0628\u0647 \u0642\u0633\u0645\u062a \u0633\u0648\u0645 \u0627\u06cc\u0646 \u0633\u0631\u06cc\u0627\u0644 \u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f! \u062f\u0631 \u0627\u06cc\u0646 \u0628\u062e\u0634\u060c \u0628\u0647 \u0622\u0632\u0645\u0627\u06cc\u0634\u200c\u0647\u0627 \u0648 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u062e\u0637 \u0644\u0648\u0644\u0647 \u062f\u0631 Google Cloud \u0645\u06cc\u200c\u067e\u0631\u062f\u0627\u0632\u06cc\u0645\u060c \u0628\u0647\u200c\u0648\u06cc\u0698\u0647 \u0628\u0631 &hellip;<\/p>\n","protected":false},"author":2,"featured_media":75697,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"","fifu_image_alt":"","footnotes":""},"categories":[339],"tags":[],"class_list":["post-75696","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev"],"_links":{"self":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts\/75696","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/comments?post=75696"}],"version-history":[{"count":0,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts\/75696\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/media\/75697"}],"wp:attachment":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/media?parent=75696"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/categories?post=75696"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/tags?post=75696"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}