{"id":390450,"date":"2024-06-29T09:15:22","date_gmt":"2024-06-29T09:15:22","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=390450"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=390450","title":{"rendered":"<span>Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u043b\u044f \u0441\u0430\u043c\u044b\u0445 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u042d\u0442\u043e \u043c\u043e\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u043e\u0441\u0442 \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0435, \u0434\u0430\u0432\u043d\u043e \u0447\u0438\u0442\u0430\u044e, \u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0441\u0435 \u043d\u0435 \u0440\u0435\u0448\u0430\u043b\u0441\u044f, \u043d\u043e, \u043a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430-\u0442\u043e \u0432\u0441\u0435 \u0432 \u0436\u0438\u0437\u043d\u0438 \u0431\u044b\u0432\u0430\u0435\u0442 \u0432 \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437.<\/p>\n<h2>\u041a\u043e\u0440\u043e\u0442\u043a\u043e \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435<\/h2>\n<ul>\n<li>\n<p>\u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c Gitlab \u0434\u043b\u044f \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u0438 CI-CD \u043a\u0430\u043a \u0443 \u0432\u0437\u0440\u043e\u0441\u043b\u044b\u0445 \u0434\u044f\u0434\u044c (\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0432\u044b\u0440\u0430\u0436\u0430\u044f\u0441\u044c)<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0435 Hello world web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (\u0431\u0435\u0437 \u0438\u0437\u043b\u0438\u0448\u0435\u0441\u0442\u0432, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u043f\u0440\u043e\u0441\u0442\u043e)<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043c \u043d\u0430\u0448\u0435 web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 Cordova (\u043a\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043c\u0435\u0442\u043e\u0434, \u0434\u043b\u044f \u043d\u0435 \u0432\u043e\u0432\u043b\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u0432 \u0438\u043d\u0434\u0443\u0441\u0442\u0440\u0438\u044e \u043b\u044e\u0434\u0435\u0439)<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0431\u0435\u0440\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e .apk \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430 Android-\u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435<\/p>\n<\/li>\n<\/ul>\n<h2>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440<\/h2>\n<p>Web- \u0438 Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043c\u043e\u0438\u043c\u0438 \u043f\u0440\u044f\u043c\u044b\u043c\u0438 \u0434\u043e\u043b\u0436\u043d\u043e\u0441\u0442\u043d\u044b\u043c\u0438 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u044d\u0442\u043e \u043c\u043e\u0435 \u0445\u043e\u0431\u0431\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0435 \u043e\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u043f\u0440\u043e\u0447\u0438\u0445 \u0434\u0435\u043b \u0432\u0440\u0435\u043c\u044f, \u044f \u043f\u043e\u043d\u0438\u043c\u0430\u044e, \u0447\u0442\u043e \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0433\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u043d\u0442\u0438\u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0432 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0432\u044b \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u0438\u0442\u0435 \u043c\u043d\u0435 \u0432\u0441\u0435 \u043d\u044e\u0430\u043d\u0441\u044b \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445! \u0426\u0435\u043b\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431\u0449\u0443\u044e \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044e \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0432\u044b\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439<\/p>\n<h2>\u0413\u043b\u0430\u0432\u0430 1. Gitlab CI-CD<\/h2>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u2014 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441 Gitlab-CE \u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u044b \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0448 \u043a\u043e\u0434, \u0438\u043c\u0435\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0432\u0435\u0440\u0441\u0438\u0439 \u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432.<\/p>\n<p>\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439 (Docker + Docker Compose) \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0434\u0435\u043f\u043b\u043e\u044f Gitlab \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e Gitlab-CE \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u043d\u043d\u0435\u0440\u043e\u0432 (\u0432 \u043c\u043e\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u2014 3), \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u043e\u0434, \u043d\u043e \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 (\u0442\u0430\u0431\u043b\u0438\u0446\u0430 1).<\/p>\n<p>\u0442\u0430\u0431\u043b\u0438\u0446\u0430 1 \u2014 \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043e\u0431\u0440\u0430\u0437\u044b<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td data-colwidth=\"130\" width=\"130\">\n<p align=\"left\"><strong>\u041d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435<\/strong><\/p>\n<\/td>\n<td data-colwidth=\"319\" width=\"319\">\n<p align=\"left\"><strong>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Docker hub<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\"><strong>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"130\" width=\"130\">\n<p align=\"left\">Gitlab-CE<\/p>\n<\/td>\n<td data-colwidth=\"319\" width=\"319\">\n<p align=\"left\"><a href=\"https:\/\/hub.docker.com\/r\/gitlab\/gitlab-ce\" rel=\"noopener noreferrer nofollow\">https:\/\/hub.docker.com\/r\/gitlab\/gitlab-ce<\/a><\/p>\n<\/td>\n<td>\n<p align=\"left\">gitlab-ce server 16.1.0-ce.0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"130\" width=\"130\">\n<p align=\"left\">Gitlab Runner<\/p>\n<\/td>\n<td data-colwidth=\"319\" width=\"319\">\n<p align=\"left\"><a href=\"https:\/\/hub.docker.com\/r\/gitlab\/gitlab-runner\" rel=\"noopener noreferrer nofollow\">https:\/\/hub.docker.com\/r\/gitlab\/gitlab-runner<\/a><\/p>\n<\/td>\n<td>\n<p align=\"left\">gitlab build runner\u00a0<code>alpine3.18-v16.1.0 shell<\/code><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c web- \u0438 android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0437 Gitlab Runner \u043f\u043e\u0434 \u0441\u0432\u043e\u0438 \u043d\u0443\u0436\u0434\u044b; \u0442\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0432\u0437\u044f\u043b\u0438 \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0432\u0435\u0440\u0441\u0438\u044e Alpine, \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u0441\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 Dockerfile, \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435:<\/p>\n<pre><code class=\"bash\">FROM gitlab\/gitlab-runner:alpine3.18-v16.1.0  # set LANG env var ENV LANG=C.UTF-8  #add Glibc 2.34 for Alpine linux RUN ALPINE_GLIBC_BASE_URL=\"https:\/\/github.com\/sgerrand\/alpine-pkg-glibc\/releases\/download\" &amp;&amp; \\     ALPINE_GLIBC_PACKAGE_VERSION=\"2.34-r0\" &amp;&amp; \\     ALPINE_GLIBC_BASE_PACKAGE_FILENAME=\"glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk\" &amp;&amp; \\     ALPINE_GLIBC_BIN_PACKAGE_FILENAME=\"glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk\" &amp;&amp; \\     ALPINE_GLIBC_I18N_PACKAGE_FILENAME=\"glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk\" &amp;&amp; \\     apk add --no-cache --virtual=.build-dependencies wget ca-certificates &amp;&amp; \\     echo \\         \"-----BEGIN PUBLIC KEY-----\\         MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApZ2u1KJKUu\/fW4A25y9m\\         y70AGEa\/J3Wi5ibNVGNn1gT1r0VfgeWd0pUybS4UmcHdiNzxJPgoWQhV2SSW1JYu\\         tOqKZF5QSN6X937PTUpNBjUvLtTQ1ve1fp39uf\/lEXPpFpOPL88LKnDBgbh7wkCp\\         m2KzLVGChf83MS0ShL6G9EQIAUxLm99VpgRjwqTQ\/KfzGtpke1wqws4au0Ab4qPY\\         KXvMLSPLUp7cfulWvhmZSegr5AdhNw5KNizPqCJT8ZrGvgHypXyiFvvAH5YRtSsc\\         Zvo9GI2e2MaZyo9\/lvb+LbLEJZKEQckqRj4P26gmASrZEPStwc+yqy1ShHLA0j6m\\         1QIDAQAB\\         -----END PUBLIC KEY-----\" | sed 's\/   *\/\\n\/g' > \"\/etc\/apk\/keys\/sgerrand.rsa.pub\" &amp;&amp; \\     wget \\         \"$ALPINE_GLIBC_BASE_URL\/$ALPINE_GLIBC_PACKAGE_VERSION\/$ALPINE_GLIBC_BASE_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_BASE_URL\/$ALPINE_GLIBC_PACKAGE_VERSION\/$ALPINE_GLIBC_BIN_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_BASE_URL\/$ALPINE_GLIBC_PACKAGE_VERSION\/$ALPINE_GLIBC_I18N_PACKAGE_FILENAME\" &amp;&amp; \\     mv \/etc\/nsswitch.conf \/etc\/nsswitch.conf.bak &amp;&amp; \\     apk add --no-cache --force-overwrite \\         \"$ALPINE_GLIBC_BASE_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_BIN_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_I18N_PACKAGE_FILENAME\" &amp;&amp; \\     \\     mv \/etc\/nsswitch.conf.bak \/etc\/nsswitch.conf &amp;&amp; \\     rm \"\/etc\/apk\/keys\/sgerrand.rsa.pub\" &amp;&amp; \\     (\/usr\/glibc-compat\/bin\/localedef --force --inputfile POSIX --charmap UTF-8 \"$LANG\" || true) &amp;&amp; \\     echo \"export LANG=$LANG\" > \/etc\/profile.d\/locale.sh &amp;&amp; \\     \\     apk del glibc-i18n &amp;&amp; \\     \\     rm \"\/root\/.wget-hsts\" &amp;&amp; \\     apk del .build-dependencies &amp;&amp; \\     rm \\         \"$ALPINE_GLIBC_BASE_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_BIN_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_I18N_PACKAGE_FILENAME\"  # set env vars ENV ANDROID_SDK_ROOT \"\/opt\/sdk\" ENV ANDROID_HOME ${ANDROID_SDK_ROOT} ENV PATH $PATH:${ANDROID_SDK_ROOT}\/gradle\/6.5\/bin:${ANDROID_SDK_ROOT}\/cmdline-tools\/latest_supported\/bin:${ANDROID_SDK_ROOT}\/platform-tools:${ANDROID_SDK_ROOT}\/extras\/google\/instantapps:${ANDROID_SDK_ROOT}\/build-tools\/34.0.0  # add core apps and libs (jdk8, jdk11, cordova10) RUN apk add --no-cache --update \\     docker docker-compose openrc doas nodejs-current npm curl python3 python3-dev py3-pip gcc musl-dev openjdk8 openjdk11 curl unzip wget RUN python3 -m pip install --upgrade --no-cache semgrep &amp;&amp; \\     npm install -g cordova@10 RUN rc-update add docker boot RUN echo 'permit nopass gitlab-runner as root' > \/etc\/doas.d\/doas.conf  # add Gradle 6.5 RUN wget -q https:\/\/services.gradle.org\/distributions\/gradle-6.5-all.zip -O \/tmp\/gradle.zip &amp;&amp; \\     mkdir -p ${ANDROID_SDK_ROOT}\/gradle &amp;&amp; \\     unzip -qq \/tmp\/gradle.zip -d ${ANDROID_SDK_ROOT}\/gradle &amp;&amp; \\     mv ${ANDROID_SDK_ROOT}\/gradle\/* ${ANDROID_SDK_ROOT}\/gradle\/6.5 &amp;&amp; \\     rm -v \/tmp\/gradle.zip  # add latest android command line tools RUN wget -q https:\/\/dl.google.com\/android\/repository\/commandlinetools-linux-9477386_latest.zip -O \/tmp\/tools.zip &amp;&amp; \\     mkdir -p ${ANDROID_SDK_ROOT}\/cmdline-tools &amp;&amp; \\     unzip -qq \/tmp\/tools.zip -d ${ANDROID_SDK_ROOT}\/cmdline-tools &amp;&amp; \\     mv ${ANDROID_SDK_ROOT}\/cmdline-tools\/* ${ANDROID_SDK_ROOT}\/cmdline-tools\/latest_supported &amp;&amp; \\     rm -v \/tmp\/tools.zip &amp;&amp; \\     mkdir -p ~\/.android\/ &amp;&amp; touch ~\/.android\/repositories.cfg  # add android platform tools, build tools 34.0.0 RUN yes | sdkmanager --sdk_root=${ANDROID_SDK_ROOT} --licenses &amp;&amp; \\     sdkmanager --sdk_root=${ANDROID_SDK_ROOT} --install \"platform-tools\" \"extras;google;instantapps\" \"build-tools;34.0.0\"  # remove jdk11 RUN apk del openjdk11  # fix build tools \"dx\" bug RUN mv \/opt\/sdk\/build-tools\/34.0.0\/d8 \/opt\/sdk\/build-tools\/34.0.0\/dx &amp;&amp;\\     mv \/opt\/sdk\/build-tools\/34.0.0\/lib\/d8.jar \/opt\/sdk\/build-tools\/34.0.0\/lib\/dx.jar  # set ownership of android sdk to gitlab-runner user RUN chown gitlab-runner -R \/opt\/sdk  # set default jdk to jdk8 ENV JAVA_HOME \"\/usr\/lib\/jvm\/java-1.8-openjdk\" ENV PATH $PATH:${JAVA_HOME}\/bin <\/code><\/pre>\n<p>\u0418\u0437 \u043d\u0435\u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Glibc (\u0441\u0442\u0440\u043e\u043a\u0430 6)<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 jdk8 \u0438 jdk11 (\u0441\u0442\u0440\u043e\u043a\u0430 52)<\/p>\n<\/li>\n<li>\n<p>\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 jdk11 (\u0441\u0442\u0440\u043e\u043a\u0430 79)<\/p>\n<\/li>\n<li>\n<p>\u0444\u0438\u043a\u0441 \u043d\u044d\u0439\u043c\u0438\u043d\u0433\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 Android SDK (\u0441\u0442\u0440\u043e\u043a\u0430 82)<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443. Glibc \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 Cordova (\u044f \u043d\u0435 \u0441\u0442\u0430\u043b \u0438\u0441\u043a\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 \u0438 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0438\u0437 Github). Jdk11 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Android command line tools, \u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u043c\u044b \u0435\u0433\u043e \u0443\u0434\u0430\u043b\u0438\u043c, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0443\u0434\u0435\u043c Cordova 10, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0440\u0443\u0436\u0438\u0442 \u0441 jdk8 (\u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043d\u0435 \u0440\u0443\u0433\u0430\u0439\u0442\u0435 \u0437\u0430 \u043b\u0435\u0433\u0430\u0441\u0438, \u0434\u0430, \u044f \u0442\u043e\u0436\u0435 \u0441\u043b\u044b\u0448\u0430\u043b \u0448\u0443\u0442\u043a\u0443 \u0412\u043b\u0430\u0434\u0430 \u0422\u044d\u043d\u0430 \u0432 \u043f\u043e\u0434\u043a\u0430\u0441\u0442\u0435, \u0433\u0434\u0435 \u043e\u043d \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u0442 \u0432\u043b\u0430\u0436\u043d\u044b\u0435 \u0444\u0430\u043d\u0442\u0430\u0437\u0438\u0438 \u043e AI \u0444\u0440\u0430\u0437\u043e\u0439 \u0432 \u0434\u0443\u0445\u0435 \u00ab\u041a\u0430\u043a\u043e\u0439 \u043a \u0447\u0435\u0440\u0442\u0443 AI, \u043b\u044e\u0434\u0438 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 8 \u0434\u0436\u0430\u0432\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f!\u00bb). \u0424\u0438\u043a\u0441 \u043d\u044d\u0439\u043c\u0438\u043d\u0433\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 Android SDK \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b Gradle \u043d\u0435 \u043f\u0430\u0434\u0430\u043b \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 \u0430\u043d\u0434\u0440\u043e\u0438\u0434-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u0432\u044b\u0448\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 Nodejs, Python, Semgrep \u0438 Gradle \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0440\u044f\u0434 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439 (\u0432 Dockerfile \u0435\u0441\u0442\u044c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u043d\u0435 \u0431\u0443\u0434\u0443 \u0438\u0445 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c)<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u0441\u0435 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043c\u043f\u0440\u043e\u0432\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 \u0432 \u0434\u043e\u043c\u0430\u0448\u043d\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c docker-compose.yml<\/p>\n<pre><code class=\"yaml\">version: \"3.9\"  networks:   gitlab_ce:     driver: bridge  volumes:   gitlab_conf:   gitlab_data:   gitlab_logs:   build_runner_home:   build_runner_conf:   test_runner_home:   test_runner_conf:   deploy_runner_home:   deploy_runner_conf:  services:   # gitlab-ce   gitlab-ce:     image: gitlab\/gitlab-ce:16.1.0-ce.0     shm_size: '2gb'     container_name: gitlab-ce     hostname: gitlab-ce.local     restart: always     depends_on:       - build-runner       - test-runner       - deploy-runner     volumes:       - gitlab_conf:\/etc\/gitlab       - gitlab_data:\/var\/opt\/gitlab       - gitlab_logs:\/var\/log\/gitlab     ports:       - \"127.0.0.1:22:22\"       - \"127.0.0.1:80:80\"     networks:       - gitlab_ce     deploy:       resources:         limits:           cpus: \"4\"           memory: 8G    # gitlab-build-runner   build-runner:     build: .\/     container_name: gitlab-build-runner     hostname: gitlab-build-runner.local     restart: always     volumes:       - build_runner_conf:\/etc\/gitlab-runner       - build_runner_home:\/home\/gitlab-runner       - \/var\/run\/docker.sock:\/var\/run\/docker.sock:rw     networks:       - gitlab_ce     deploy:       resources:         limits:           cpus: \"4\"           memory: 4G    # gitlab-test-runner   test-runner:     build: .\/     container_name: gitlab-test-runner     hostname: gitlab-test-runner.local     restart: always     volumes:       - test_runner_conf:\/etc\/gitlab-runner       - test_runner_home:\/home\/gitlab-runner       - \/var\/run\/docker.sock:\/var\/run\/docker.sock:rw     networks:       - gitlab_ce     deploy:       resources:         limits:           cpus: \"1\"           memory: 1G    # gitlab-deploy-runner   deploy-runner:     build: .\/     container_name: gitlab-deploy-runner     hostname: gitlab-deploy-runner.local     restart: always     volumes:       - deploy_runner_conf:\/etc\/gitlab-runner       - deploy_runner_home:\/home\/gitlab-runner       - \/var\/run\/docker.sock:\/var\/run\/docker.sock:rw     networks:       - gitlab_ce     deploy:       resources:         limits:           cpus: \"1\"           memory: 1G <\/code><\/pre>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0435\u043a\u0446\u0438\u044e deploy \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435, \u0432 \u043d\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0442\u0438\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441, \u0442\u0430\u043a\u0436\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u043d\u0430 build: \u0437\u0434\u0435\u0441\u044c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u0438\u0437 \u043a\u0430\u043a\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0437 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (\u0433\u0434\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f Dockerfile), \u043d\u0435 \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u0435 shm_size \u2014 \u044d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u043f\u043e\u0432\u044b\u0441\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Gitlab.<\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u043b\u043e\u0436\u0435\u043d\u0430 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u043f\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u0440\u0430\u043d\u043d\u0435\u0440\u043e\u0432 (\u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0438 \u043e\u0434\u043d\u0438\u043c, \u0438\u043b\u0438 \u0436\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0430\u0434\u0438\u0438 (build, test, deploy) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437, \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443) \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u0430 c \u0442\u0438\u043f\u043e\u043c docker, \u043e\u0434\u043d\u0430\u043a\u043e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e \u0447\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c\u0438, \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043a\u0430\u043a shell-\u0440\u0430\u043d\u043d\u0435\u0440\u044b.  \u0414\u0430, \u0437\u0434\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u043c\u043f\u0440\u043e\u0432\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 docker in docker (\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430 \u0435\u0441\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043a \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0435 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438\u0437-\u0437\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c\u044e, \u043d\u043e \u0432 \u0446\u0435\u043b\u044f\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430, \u0434\u0443\u043c\u0430\u044e, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0438 \u0442\u0430\u043a\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e).<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u0430 (\u043a\u0430\u043a \u0432\u044b \u0437\u043d\u0430\u0435\u0442\u0435, \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0440\u0430\u043d\u043d\u0435\u0440, \u0435\u0433\u043e \u0435\u0449\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 Gitlab)<\/p>\n<pre><code class=\"bash\">#!\/bin\/sh  RUNNER_CONTAINER_ID=$1 RUNNER_TAG=$2 GITLAB_RUNNER_REG_TOKEN=$3  GITLAB_SUBNET=$(docker network ls | grep gitlab_ce | cut -d \" \" -f 4)  echo \"Registering ...\";  docker exec -it $RUNNER_CONTAINER_ID bash -c 'gitlab-runner register \\   --non-interactive \\   --executor \"shell\" \\   --docker-image alpine:latest \\   --url \"http:\/\/gitlab-ce.local\/\" \\   --registration-token \"'$GITLAB_RUNNER_REG_TOKEN'\" \\   --description \"docker-'$RUNNER_TAG'-runner\" \\   --maintenance-note \"Docker runner for gitlab-ce\" \\   --tag-list \"docker,'$RUNNER_TAG'\" \\   --run-untagged=\"true\" \\   --locked=\"false\" \\   --access-level=\"not_protected\" > \/dev\/null 2>&amp;1; \\   echo \"    network_mode = \\\"'$GITLAB_SUBNET'\\\"\" >> \/etc\/gitlab-runner\/config.toml';   echo \"Done\" <\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 id \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441 \u0440\u0430\u043d\u043d\u0435\u0440\u043e\u043c, \u0442\u044d\u0433 \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d. \u0412 \u0445\u043e\u0434\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u0430, \u0442\u0430\u043a\u0436\u0435 \u0432\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043f\u0440\u0430\u0432\u043a\u0430 \u0432 \u0435\u0433\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e, \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u0435\u0442\u044c, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0435\u043c\u0443 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0441\u0435\u0440\u0432\u0435\u0440 Gitlab.<\/p>\n<p>\u041f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0432\u043e\u0435\u0433\u043e \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430 Gitlab, \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442, \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0432\u0441\u0435 \u0432 \u0435\u0434\u0438\u043d\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0440\u0443\u0442\u0438\u043d\u0443.<\/p>\n<pre><code class=\"bash\">#!\/bin\/sh  echo \"################### Build &amp; deploy Gitlab-CE ###################\" docker compose -p gitlab-ce up -d --build --wait gitlab-ce echo \"###############################################################\"  echo \"...\"  echo \"#################### Check Gitlab-CE state ####################\" docker compose -p gitlab-ce ps echo \"###############################################################\"  echo \"...\"  echo \"############## Gitlab runner registration token ###############\" RUNNER_REG_TOKEN=$(docker exec -it gitlab-ce gitlab-rails runner -e production 'puts Gitlab::CurrentSettings.current_application_settings.runners_registration_token') echo \"Token: $RUNNER_REG_TOKEN\" echo \"###############################################################\"  echo \"...\"  echo \"################ Gitlab initial root password #################\" docker exec -it gitlab-ce bash -c 'grep 'Password:' \/etc\/gitlab\/initial_root_password 2>\/dev\/null || echo \"Custom root password already exists.\"' echo \"###############################################################\"  echo \"...\"  echo \"################# Base runners registration ###################\" echo \"Registering  gitlab-build-runner ...\" .\/reg_new_runner.sh gitlab-build-runner build $RUNNER_REG_TOKEN echo \"Registering  gitlab-test-runner ...\" .\/reg_new_runner.sh gitlab-test-runner test $RUNNER_REG_TOKEN echo \"Registering  gitlab-deploy-runner ...\" .\/reg_new_runner.sh gitlab-deploy-runner deploy $RUNNER_REG_TOKEN echo \"###############################################################\" <\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a \u0442\u0435\u0441\u0442\u0430\u043c Gitlab-\u0438\u043d\u0441\u0442\u0430\u043d\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a7b\/12e\/0ee\/a7b12e0ee02b136f4f3db4ce7b0fe23d.png\" alt=\"\u0437\u0430\u0440\u0435\u0433\u0435\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u044b\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u044b\" title=\"\u0437\u0430\u0440\u0435\u0433\u0435\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u044b\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u044b\" width=\"1302\" height=\"477\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a7b\/12e\/0ee\/a7b12e0ee02b136f4f3db4ce7b0fe23d.png\"\/><\/p>\n<div><figcaption>\u0437\u0430\u0440\u0435\u0433\u0435\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u044b\u0435 \u0440\u0430\u043d\u043d\u0435\u0440\u044b<\/figcaption><\/div>\n<\/figure>\n<h3>\u0413\u043b\u0430\u0432\u0430 2. \u041f\u0440\u043e\u0441\u0442\u043e\u0435 web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h3>\n<p>\u041a\u0430\u043a \u0432\u044b \u0443\u0436\u0435, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u0434\u043e\u0433\u0430\u0434\u0430\u043b\u0438\u0441\u044c, \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0435 web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0441\u043e\u0431\u0435\u0440\u0435\u043c \u0435\u0433\u043e \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 Webpack, \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443 \u0435\u0441\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u0445\u043e\u0440\u043e\u0448\u0438\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432, <a href=\"https:\/\/webpack.js.org\/guides\/getting-started\" rel=\"noopener noreferrer nofollow\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0442\u043e\u0436\u0435 \u043d\u0430 \u0432\u044b\u0441\u043e\u0442\u0435.<\/a><\/p>\n<p>\u041e\u0442 \u0441\u0435\u0431\u044f \u043b\u0438\u0448\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u044e \u043f\u0430\u0440\u0443 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u043e\u0432 \u0438\u0437 \u0441\u0432\u043e\u0438\u0445 pet-\u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u0443 \u043c\u0435\u043d\u044f.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0bc\/566\/7cd\/0bc5667cd8d81082db04640f4d4a6c0e.png\" alt=\"\u0444\u0430\u0439\u043b\u044b web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u044b \u043a\u0440\u0430\u0441\u043d\u044b\u043c\" title=\"\u0444\u0430\u0439\u043b\u044b web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u044b \u043a\u0440\u0430\u0441\u043d\u044b\u043c\" width=\"1305\" height=\"448\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0bc\/566\/7cd\/0bc5667cd8d81082db04640f4d4a6c0e.png\"\/><\/p>\n<div><figcaption>\u0444\u0430\u0439\u043b\u044b web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u044b \u043a\u0440\u0430\u0441\u043d\u044b\u043c<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a2e\/407\/377\/a2e407377c3fdf612e96629981a5acb6.png\" alt=\"\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u043f\u0430\u043f\u043a\u0438 src\" title=\"\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u043f\u0430\u043f\u043a\u0438 src\" width=\"1273\" height=\"405\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a2e\/407\/377\/a2e407377c3fdf612e96629981a5acb6.png\"\/><\/p>\n<div><figcaption>\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u043f\u0430\u043f\u043a\u0438 src<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0435 \u0431\u0443\u0434\u0443 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u044d\u0442\u043e\u043c \u043f\u0443\u043d\u043a\u0442\u0435, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u043d\u0430 \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0449\u0443 \u0432\u0430\u0448\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0437\u0430\u0434\u0430\u0439\u0442\u0435 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u0412\u0430\u0448 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434, \u043f\u0430\u043f\u043a\u0443 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c www, \u044d\u0442\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/682\/074\/0a8\/6820740a828d96b86084a4d8f11ab442.png\" alt=\"\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f webpack\" title=\"\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f webpack\" width=\"1249\" height=\"531\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/682\/074\/0a8\/6820740a828d96b86084a4d8f11ab442.png\"\/><\/p>\n<div><figcaption>\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f webpack<\/figcaption><\/div>\n<\/figure>\n<h2>\u0413\u043b\u0430\u0432\u0430 3. Hi Cordova, pls transform my website to android app<\/h2>\n<p>\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0435 \u0438\u0442\u043e\u0433\u0438: \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0435 web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 Gitlab, \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0431\u0435\u0440\u0435\u043c \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0430\u0437\u043b\u0430 \u0432\u043e\u0435\u0434\u0438\u043d\u043e.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b config.xml \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u044f \u043f\u043e\u043b\u043e\u0436\u0443 \u0435\u0433\u043e \u0432 \u043f\u0430\u043f\u043a\u0443 Cordova).<\/p>\n<pre><code class=\"xml\">&lt;?xml version='1.0' encoding='utf-8'?> &lt;widget id=\"com.moviefinder.main\" version=\"1.0.0\" xmlns=\"http:\/\/www.w3.org\/ns\/widgets\" xmlns:cdv=\"http:\/\/cordova.apache.org\/ns\/1.0\" xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\">     &lt;name>Hello-world-app&lt;\/name>     &lt;description>My first app&lt;\/description>     &lt;author email=\"username@domain.com\" href=\"https:\/\/link-to-my.app\">         Name Surname     &lt;\/author>          &lt;preference name=\"android-targetSdkVersion\" value=\"34\" \/>     &lt;preference name=\"android-minSdkVersion\" value=\"21\" \/>          &lt;preference name=\"AndroidPersistentFileLocation\" value=\"Compatibility\" \/>          &lt;preference name=\"DisallowOverscroll\" value=\"true\" \/>          &lt;allow-navigation href=\"*\" \/>     &lt;allow-intent href=\"*\" \/>     &lt;access origin=\"*\" \/>          &lt;edit-config file=\"app\/src\/main\/AndroidManifest.xml\" mode=\"merge\" target=\"\/manifest\/application\/activity\">         &lt;activity android:exported=\"true\"\/>     &lt;\/edit-config>    &lt;\/widget> <\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0435\u043a\u0446\u0438\u044e edit-config: \u0432 \u043d\u0435\u0439 \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 android:exported=&#187;true&#187; \u2014 \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445 Android.<\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u0448\u0435 \u0430\u043d\u0434\u0440\u043e\u0438\u0434-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u2014 \u044d\u0442\u043e \u043f\u043e \u0444\u0430\u043a\u0442\u0443 \u0435\u0449\u0435 \u0438 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0431\u043e\u0440\u043a\u0443 web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 Nginx-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435, \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043c\u044b \u0441\u0440\u0430\u0437\u0443 \u043c\u043e\u0433\u043b\u0438 \u0432\u0438\u0434\u0435\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0430\u0448\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u043d\u0435\u0442 \u043f\u043e\u0434 \u0440\u0443\u043a\u043e\u0439 android-\u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 \u0438\u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435), \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c Dockerfile \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c:<\/p>\n<pre><code class=\"bash\">FROM nginx COPY .\/www \/usr\/share\/nginx\/html <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u043d\u0430\u0448\u0438\u043c web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c (\u0440\u0430\u043d\u0435\u0435 \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u043b\u0438 \u043d\u0430\u0448 web-\u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u043f\u0430\u043f\u043a\u0443 www)<\/p>\n<p>\u041f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c .gitlab-ci.yml \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e!<\/p>\n<pre><code class=\"yaml\">stages:   - build   - test   - deploy  build-code-job:   stage: build   tags:     - build     - docker   before_script:     - curl \"https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendMessage?chat_id=$TELEGRAM_CHAT_ID&amp;text=%20?%20%5B$CI_PROJECT_NAME%5D%20Build%20job%20started\"   script:     - PATH=$PATH:\/opt\/sdk\/gradle\/6.5\/bin     - mkdir -p ~\/.android\/ &amp;&amp; touch ~\/.android\/repositories.cfg     - npm i     - npm run build     - doas docker build -t $CI_PROJECT_NAME .     - cordova create ${CI_PROJECT_NAME}     - cd ${CI_PROJECT_NAME}     - rm -Rf .\/www\/*     - cp -r ..\/www\/* .\/www\/     - cp ..\/cordova\/* .\/     - cordova platform add android     - cordova build android   cache:     paths:       - node_modules   artifacts:     paths:       - .\/${CI_PROJECT_NAME}\/platforms\/android     expire_in: 1 week     name: ${CI_PROJECT_NAME}_${CI_JOB_ID}_android   after_script:     - >       if [ $CI_JOB_STATUS == 'success' ]; then         curl \"https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendMessage?chat_id=$TELEGRAM_CHAT_ID&amp;text=%20\u2705%20%5B$CI_PROJECT_NAME%5D%20Build%20job%20completed\"         curl -F document=@\".\/${CI_PROJECT_NAME}\/platforms\/android\/app\/build\/outputs\/apk\/debug\/app-debug.apk\" https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendDocument?chat_id=$TELEGRAM_CHAT_ID       else         curl \"https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendMessage?chat_id=$TELEGRAM_CHAT_ID&amp;text=%20\u274c%20%5B$CI_PROJECT_NAME%5D%20Build%20job%20failed%20$CI_PIPELINE_URL\"       fi  test-code-job:   stage: test   tags:     - test     - docker   script:     - doas docker image ls | grep \"$CI_PROJECT_NAME\"     - semgrep scan src --config auto --output $CI_PROJECT_NAME-sast-report.json --json   artifacts:     paths:       - $CI_PROJECT_NAME-sast-report.json     expire_in: 4 week     name: ${CI_PROJECT_NAME}_${CI_JOB_ID}_sast_report   after_script:     - >       if [ $CI_JOB_STATUS == 'success' ]; then         curl \"https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendMessage?chat_id=$TELEGRAM_CHAT_ID&amp;text=%20\u2705%20%5B$CI_PROJECT_NAME%5D%20All%20tests%20passed%20successfuly\"         curl -F document=@\"$CI_PROJECT_NAME-sast-report.json\" https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendDocument?chat_id=$TELEGRAM_CHAT_ID       else         curl \"https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendMessage?chat_id=$TELEGRAM_CHAT_ID&amp;text=%20\u274c%20%5B$CI_PROJECT_NAME%5D%20Tests%20failed%20$CI_PIPELINE_URL\"       fi  deploy-code-job:   stage: deploy   tags:     - deploy     - docker   script:     - doas docker stop $CI_PROJECT_NAME || true &amp;&amp; doas docker rm $CI_PROJECT_NAME || true     - doas docker run -d --name $CI_PROJECT_NAME -p $HOST_PORT:80 --restart unless-stopped $CI_PROJECT_NAME   after_script:     - >       if [ $CI_JOB_STATUS == 'success' ]; then         curl \"https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendMessage?chat_id=$TELEGRAM_CHAT_ID&amp;text=%20?%20%5B$CI_PROJECT_NAME%5D%20Deploy%20job%20completed%20$PROJECT_URL\"       else         curl \"https:\/\/api.telegram.org\/bot$TELEGRAM_BOT_TOKEN\/sendMessage?chat_id=$TELEGRAM_CHAT_ID&amp;text=%20\u274c%20%5B$CI_PROJECT_NAME%5D%20Deploy%20job%20failed%20$CI_PIPELINE_URL\"       fi <\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 3 \u0448\u0430\u0433\u0430:<\/p>\n<ul>\n<li>\n<p>build<\/p>\n<\/li>\n<li>\n<p>test<\/p>\n<\/li>\n<li>\n<p>deploy<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u044b, \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435, \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u044d\u0442\u0430\u043f\u0435, \u043d\u043e \u044f \u043f\u043e\u044f\u0441\u043d\u044e \u043d\u044e\u0430\u043d\u0441\u044b: \u043f\u043e\u043c\u0438\u043c\u043e \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u0431\u043e\u0440\u043a\u0438, \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 Telegram-\u043a\u0430\u043d\u0430\u043b. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0432 after_script \u2014 [ $CI_JOB_STATUS == &#8216;success&#8217; ] \u2014 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u043c, \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u043b\u0438 \u0432\u0441\u0435 \u0448\u0430\u0433\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u043b\u0438 \u0436\u0435 \u0435\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438, \u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b; \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438 \u0441\u0431\u043e\u0440\u043a\u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430 \u043f\u0430\u043f\u043a\u0443 \u0441 \u0430\u043d\u0434\u0440\u043e\u0438\u0434-\u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u2014 \u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0432 Android Studio, \u0430 \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0442\u0447\u0435\u0442 SAST-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f (\u0432\u043e\u0442, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u043d\u0430\u043c \u0438 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u0441\u044f Python \u0438 Semgrep)<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0438 \u0432 \u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f apk-\u0444\u0430\u0439\u043b \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f SAST \u043e\u0442\u0447\u0435\u0442 \u0442\u0430\u043a\u0436\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f9d\/40f\/4b4\/f9d40f4b4afae7aad7627723b7a02b70.png\" alt=\"\u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0439 \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\" title=\"\u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0439 \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\" width=\"976\" height=\"319\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f9d\/40f\/4b4\/f9d40f4b4afae7aad7627723b7a02b70.png\"\/><\/p>\n<div><figcaption>\u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0439 \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 .apk \u0444\u0430\u0439\u043b \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435 \u0438 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0430 \u0442\u043e\u0442 \u0444\u0430\u043a\u0442, \u0447\u0442\u043e \u0444\u0430\u0439\u043b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0432 \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440, \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0432\u0430\u0448\u0435\u0439 \u0433\u0440\u0443\u043f\u043f\u043e\u0439 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f (\u0435\u0441\u043b\u0438, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043e\u043d\u0430 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c)<\/p>\n<p>\u0418 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0448\u0442\u0440\u0438\u0445 \u2014 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f85\/845\/920\/f85845920a64c70a9820596cfe726f60.png\" alt=\"\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\" title=\"\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f\" width=\"1291\" height=\"548\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f85\/845\/920\/f85845920a64c70a9820596cfe726f60.png\"\/><\/p>\n<div><figcaption>\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0430\u043f\u0443\u0448\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bd7\/41e\/225\/bd741e225da44d809b86bf25b9fe9780.png\" width=\"1275\" height=\"524\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bd7\/41e\/225\/bd741e225da44d809b86bf25b9fe9780.png\"\/><\/figure>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u0443\u0441\u043b\u044b\u0448\u0430\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u0441\u043e\u0432\u0435\u0442\u044b \u0438 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 \u043e\u0442 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e: \u0432 \u044d\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u044f \u043d\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442, \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u0435\u043b\u044e\u0441\u044c \u0441\u0432\u043e\u0438\u043c \u0445\u043e\u0431\u0431\u0438 \u0441 \u0432\u0430\u043c\u0438.<\/p>\n<hr\/>\n<p>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u043e\u0442 \u0442\u0435\u043c\u044b: \u044f \u0432\u0435\u0434\u0443 \u043b\u044e\u0431\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043a\u0430\u043d\u0430\u043b \u043d\u0430 youtube, \u0433\u0434\u0435 \u043f\u044b\u0442\u0430\u044e\u0441\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439, \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u044f \u043e \u0441\u0432\u043e\u0438\u0445 \u043b\u044e\u0431\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u0442\u0430\u043c \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e,\u043d \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u044d\u0442\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Gitlab (\u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043f\u0440\u043e\u0448\u0443 \u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u0437\u0430 \u0441\u0432\u043e\u0439 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439, \u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0447\u0443\u0441\u044c).<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64b7fb33c0bac093f0815179\" data-style=\"\" id=\"64b7fb33c0bac093f0815179\" width=\"\"><\/div>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/749342\/\"> https:\/\/habr.com\/ru\/articles\/749342\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u042d\u0442\u043e \u043c\u043e\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u043e\u0441\u0442 \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0435, \u0434\u0430\u0432\u043d\u043e \u0447\u0438\u0442\u0430\u044e, \u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0441\u0435 \u043d\u0435 \u0440\u0435\u0448\u0430\u043b\u0441\u044f, \u043d\u043e, \u043a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430-\u0442\u043e \u0432\u0441\u0435 \u0432 \u0436\u0438\u0437\u043d\u0438 \u0431\u044b\u0432\u0430\u0435\u0442 \u0432 \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437.<\/p>\n<h2>\u041a\u043e\u0440\u043e\u0442\u043a\u043e \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435<\/h2>\n<ul>\n<li>\n<p>\u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c Gitlab \u0434\u043b\u044f \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u0438 CI-CD \u043a\u0430\u043a \u0443 \u0432\u0437\u0440\u043e\u0441\u043b\u044b\u0445 \u0434\u044f\u0434\u044c (\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0432\u044b\u0440\u0430\u0436\u0430\u044f\u0441\u044c)<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0435 Hello world web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (\u0431\u0435\u0437 \u0438\u0437\u043b\u0438\u0448\u0435\u0441\u0442\u0432, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u043f\u0440\u043e\u0441\u0442\u043e)<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043c \u043d\u0430\u0448\u0435 web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 Cordova (\u043a\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043c\u0435\u0442\u043e\u0434, \u0434\u043b\u044f \u043d\u0435 \u0432\u043e\u0432\u043b\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u0432 \u0438\u043d\u0434\u0443\u0441\u0442\u0440\u0438\u044e \u043b\u044e\u0434\u0435\u0439)<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0431\u0435\u0440\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e .apk \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430 Android-\u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435<\/p>\n<\/li>\n<\/ul>\n<h2>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440<\/h2>\n<p>Web- \u0438 Android-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043c\u043e\u0438\u043c\u0438 \u043f\u0440\u044f\u043c\u044b\u043c\u0438 \u0434\u043e\u043b\u0436\u043d\u043e\u0441\u0442\u043d\u044b\u043c\u0438 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u044d\u0442\u043e \u043c\u043e\u0435 \u0445\u043e\u0431\u0431\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0435 \u043e\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u043f\u0440\u043e\u0447\u0438\u0445 \u0434\u0435\u043b \u0432\u0440\u0435\u043c\u044f, \u044f \u043f\u043e\u043d\u0438\u043c\u0430\u044e, \u0447\u0442\u043e \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043c\u043e\u0433\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u043d\u0442\u0438\u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0432 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0432\u044b \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u0438\u0442\u0435 \u043c\u043d\u0435 \u0432\u0441\u0435 \u043d\u044e\u0430\u043d\u0441\u044b \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445! \u0426\u0435\u043b\u044c \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431\u0449\u0443\u044e \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044e \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0432\u044b\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439<\/p>\n<h2>\u0413\u043b\u0430\u0432\u0430 1. Gitlab CI-CD<\/h2>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u2014 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441 Gitlab-CE \u0438 \u0440\u0430\u043d\u043d\u0435\u0440\u044b \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0448 \u043a\u043e\u0434, \u0438\u043c\u0435\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0432\u0435\u0440\u0441\u0438\u0439 \u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432.<\/p>\n<p>\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439 (Docker + Docker Compose) \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0434\u0435\u043f\u043b\u043e\u044f Gitlab \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e Gitlab-CE \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u043d\u043d\u0435\u0440\u043e\u0432 (\u0432 \u043c\u043e\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u2014 3), \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u043e\u0434, \u043d\u043e \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 (\u0442\u0430\u0431\u043b\u0438\u0446\u0430 1).<\/p>\n<p>\u0442\u0430\u0431\u043b\u0438\u0446\u0430 1 \u2014 \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043e\u0431\u0440\u0430\u0437\u044b<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td data-colwidth=\"130\" width=\"130\">\n<p align=\"left\"><strong>\u041d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435<\/strong><\/p>\n<\/td>\n<td data-colwidth=\"319\" width=\"319\">\n<p align=\"left\"><strong>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Docker hub<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\"><strong>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"130\" width=\"130\">\n<p align=\"left\">Gitlab-CE<\/p>\n<\/td>\n<td data-colwidth=\"319\" width=\"319\">\n<p align=\"left\"><a href=\"https:\/\/hub.docker.com\/r\/gitlab\/gitlab-ce\" rel=\"noopener noreferrer nofollow\">https:\/\/hub.docker.com\/r\/gitlab\/gitlab-ce<\/a><\/p>\n<\/td>\n<td>\n<p align=\"left\">gitlab-ce server 16.1.0-ce.0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"130\" width=\"130\">\n<p align=\"left\">Gitlab Runner<\/p>\n<\/td>\n<td data-colwidth=\"319\" width=\"319\">\n<p align=\"left\"><a href=\"https:\/\/hub.docker.com\/r\/gitlab\/gitlab-runner\" rel=\"noopener noreferrer nofollow\">https:\/\/hub.docker.com\/r\/gitlab\/gitlab-runner<\/a><\/p>\n<\/td>\n<td>\n<p align=\"left\">gitlab build runner\u00a0<code>alpine3.18-v16.1.0 shell<\/code><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c web- \u0438 android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0437 Gitlab Runner \u043f\u043e\u0434 \u0441\u0432\u043e\u0438 \u043d\u0443\u0436\u0434\u044b; \u0442\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0432\u0437\u044f\u043b\u0438 \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0432\u0435\u0440\u0441\u0438\u044e Alpine, \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u0441\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 Dockerfile, \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435:<\/p>\n<pre><code class=\"bash\">FROM gitlab\/gitlab-runner:alpine3.18-v16.1.0  # set LANG env var ENV LANG=C.UTF-8  #add Glibc 2.34 for Alpine linux RUN ALPINE_GLIBC_BASE_URL=\"https:\/\/github.com\/sgerrand\/alpine-pkg-glibc\/releases\/download\" &amp;&amp; \\     ALPINE_GLIBC_PACKAGE_VERSION=\"2.34-r0\" &amp;&amp; \\     ALPINE_GLIBC_BASE_PACKAGE_FILENAME=\"glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk\" &amp;&amp; \\     ALPINE_GLIBC_BIN_PACKAGE_FILENAME=\"glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk\" &amp;&amp; \\     ALPINE_GLIBC_I18N_PACKAGE_FILENAME=\"glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk\" &amp;&amp; \\     apk add --no-cache --virtual=.build-dependencies wget ca-certificates &amp;&amp; \\     echo \\         \"-----BEGIN PUBLIC KEY-----\\         MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApZ2u1KJKUu\/fW4A25y9m\\         y70AGEa\/J3Wi5ibNVGNn1gT1r0VfgeWd0pUybS4UmcHdiNzxJPgoWQhV2SSW1JYu\\         tOqKZF5QSN6X937PTUpNBjUvLtTQ1ve1fp39uf\/lEXPpFpOPL88LKnDBgbh7wkCp\\         m2KzLVGChf83MS0ShL6G9EQIAUxLm99VpgRjwqTQ\/KfzGtpke1wqws4au0Ab4qPY\\         KXvMLSPLUp7cfulWvhmZSegr5AdhNw5KNizPqCJT8ZrGvgHypXyiFvvAH5YRtSsc\\         Zvo9GI2e2MaZyo9\/lvb+LbLEJZKEQckqRj4P26gmASrZEPStwc+yqy1ShHLA0j6m\\         1QIDAQAB\\         -----END PUBLIC KEY-----\" | sed 's\/   *\/\\n\/g' > \"\/etc\/apk\/keys\/sgerrand.rsa.pub\" &amp;&amp; \\     wget \\         \"$ALPINE_GLIBC_BASE_URL\/$ALPINE_GLIBC_PACKAGE_VERSION\/$ALPINE_GLIBC_BASE_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_BASE_URL\/$ALPINE_GLIBC_PACKAGE_VERSION\/$ALPINE_GLIBC_BIN_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_BASE_URL\/$ALPINE_GLIBC_PACKAGE_VERSION\/$ALPINE_GLIBC_I18N_PACKAGE_FILENAME\" &amp;&amp; \\     mv \/etc\/nsswitch.conf \/etc\/nsswitch.conf.bak &amp;&amp; \\     apk add --no-cache --force-overwrite \\         \"$ALPINE_GLIBC_BASE_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_BIN_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_I18N_PACKAGE_FILENAME\" &amp;&amp; \\     \\     mv \/etc\/nsswitch.conf.bak \/etc\/nsswitch.conf &amp;&amp; \\     rm \"\/etc\/apk\/keys\/sgerrand.rsa.pub\" &amp;&amp; \\     (\/usr\/glibc-compat\/bin\/localedef --force --inputfile POSIX --charmap UTF-8 \"$LANG\" || true) &amp;&amp; \\     echo \"export LANG=$LANG\" > \/etc\/profile.d\/locale.sh &amp;&amp; \\     \\     apk del glibc-i18n &amp;&amp; \\     \\     rm \"\/root\/.wget-hsts\" &amp;&amp; \\     apk del .build-dependencies &amp;&amp; \\     rm \\         \"$ALPINE_GLIBC_BASE_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_BIN_PACKAGE_FILENAME\" \\         \"$ALPINE_GLIBC_I18N_PACKAGE_FILENAME\"  # set env vars ENV ANDROID_SDK_ROOT \"\/opt\/sdk\" ENV ANDROID_HOME ${ANDROID_SDK_ROOT} ENV PATH $PATH:${ANDROID_SDK_ROOT}\/gradle\/6.5\/bin:${ANDROID_SDK_ROOT}\/cmdline-tools\/latest_supported\/bin:${ANDROID_SDK_ROOT}\/platform-tools:${ANDROID_SDK_ROOT}\/extras\/google\/instantapps:${ANDROID_SDK_ROOT}\/build-tools\/34.0.0  # add core apps and libs (jdk8, jdk11, cordova10) RUN apk add --no-cache --update \\     docker docker-compose openrc doas nodejs-current npm curl python3 python3-dev py3-pip gcc musl-dev openjdk8 openjdk11 curl unzip wget RUN python3 -m pip install --upgrade --no-cache semgrep &amp;&amp; \\     npm install -g cordova@10 RUN rc-update add docker boot RUN echo 'permit nopass gitlab-runner as root' > \/etc\/doas.d\/doas.conf  # add Gradle 6.5 RUN wget -q https:\/\/services.gradle.org\/distributions\/gradle-6.5-all.zip -O \/tmp\/gradle.zip &amp;&amp; \\     mkdir -p ${ANDROID_SDK_ROOT}\/gradle &amp;&amp; \\     unzip -qq \/tmp\/gradle.zip -d ${ANDROID_SDK_ROOT}\/gradle &amp;&amp; \\     mv ${ANDROID_SDK_ROOT}\/gradle\/* ${ANDROID_SDK_ROOT}\/gradle\/6.5 &amp;&amp; \\     rm -v \/tmp\/gradle.zip  # add latest android command line tools RUN wget -q https:\/\/dl.google.com\/android\/repository\/commandlinetools-linux-9477386_latest.zip -O \/tmp\/tools.zip &amp;&amp; \\     mkdir -p ${ANDROID_SDK_ROOT}\/cmdline-tools &amp;&amp; \\     unzip -qq \/tmp\/tools.zip -d ${ANDROID_SDK_ROOT}\/cmdline-tools &amp;&amp; \\     mv ${ANDROID_SDK_ROOT}\/cmdline-tools\/* ${ANDROID_SDK_ROOT}\/cmdline-tools\/latest_supported &amp;&amp; \\     rm -v \/tmp\/tools.zip &amp;&amp; \\     mkdir -p ~\/.android\/ &amp;&amp; touch ~\/.android\/repositories.cfg  # add android platform tools, build tools 34.0.0 RUN yes | sdkmanager --sdk_root=${ANDROID_SDK_ROOT} --licenses &amp;&amp; \\     sdkmanager --sdk_root=${ANDROID_SDK_ROOT} --install \"platform-tools\" \"extras;google;instantapps\" \"build-tools;34.0.0\"  # remove jdk11 RUN apk del openjdk11  # fix build tools \"dx\" bug RUN mv \/opt\/sdk\/build-tools\/34.0.0\/d8 \/opt\/sdk\/build-tools\/34.0.0\/dx &amp;&amp;\\     mv \/opt\/sdk\/build-tools\/34.0.0\/lib\/d8.jar \/opt\/sdk\/build-tools\/34.0.0\/lib\/dx.jar  # set ownership of android sdk to gitlab-runner user RUN chown gitlab-runner -R \/opt\/sdk  # set default jdk to jdk8 ENV JAVA_HOME \"\/usr\/lib\/jvm\/java-1.8-openjdk\" ENV PATH $PATH:${JAVA_HOME}\/bin <\/code><\/pre>\n<p>\u0418\u0437 \u043d\u0435\u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Glibc (\u0441\u0442\u0440\u043e\u043a\u0430 6)<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 jdk8 \u0438 jdk11 (\u0441\u0442\u0440\u043e\u043a\u0430 52)<\/p>\n<\/li>\n<li>\n<p>\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 jdk11 (\u0441\u0442\u0440\u043e\u043a\u0430 79)<\/p>\n<\/li>\n<li>\n<p>\u0444\u0438\u043a\u0441 \u043d\u044d\u0439\u043c\u0438\u043d\u0433\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 Android SDK (\u0441\u0442\u0440\u043e\u043a\u0430 82)<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443. Glibc \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 Cordova (\u044f \u043d\u0435 \u0441\u0442\u0430\u043b \u0438\u0441\u043a\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 \u0438 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0438\u0437 Github). Jdk11 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Android command line tools, \u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u043c\u044b \u0435\u0433\u043e \u0443\u0434\u0430\u043b\u0438\u043c, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0443\u0434\u0435\u043c Cordova 10, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0440\u0443\u0436\u0438\u0442 \u0441 jdk8 (\u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043d\u0435 \u0440\u0443\u0433\u0430\u0439\u0442\u0435 \u0437\u0430 \u043b\u0435\u0433\u0430\u0441\u0438, \u0434\u0430, \u044f \u0442\u043e\u0436\u0435 \u0441\u043b\u044b\u0448\u0430\u043b \u0448\u0443\u0442\u043a\u0443 \u0412\u043b\u0430\u0434\u0430 \u0422\u044d\u043d\u0430 \u0432 \u043f\u043e\u0434\u043a\u0430\u0441\u0442\u0435, \u0433\u0434\u0435 \u043e\u043d \u043f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u0442 \u0432\u043b\u0430\u0436\u043d\u044b\u0435 \u0444\u0430\u043d\u0442\u0430\u0437\u0438\u0438 \u043e AI \u0444\u0440\u0430\u0437\u043e\u0439 \u0432 \u0434\u0443\u0445\u0435 \u00ab\u041a\u0430\u043a\u043e\u0439 \u043a \u0447\u0435\u0440\u0442\u0443 AI, \u043b\u044e\u0434\u0438 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 8 \u0434\u0436\u0430\u0432\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f!\u00bb). \u0424\u0438\u043a\u0441 \u043d\u044d\u0439\u043c\u0438\u043d\u0433\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 Android SDK \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b Gradle \u043d\u0435 \u043f\u0430\u0434\u0430\u043b \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 \u0430\u043d\u0434\u0440\u043e\u0438\u0434-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u0432\u044b\u0448\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 Nodejs, Python, Semgrep \u0438 Gradle \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0440\u044f\u0434 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439 (\u0432 Dockerfile \u0435\u0441\u0442\u044c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u043d\u0435 \u0431\u0443\u0434\u0443 \u0438\u0445 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c)<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u0441\u0435 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043c\u043f\u0440\u043e\u0432\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 \u0432 \u0434\u043e\u043c\u0430\u0448\u043d\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c docker-compose.yml<\/p>\n<pre><code class=\"yaml\">version: \"3.9\"  networks:   gitlab_ce:     driver: bridge  volumes:   gitlab_conf:   gitlab_data:   gitlab_logs:   build_runner_home:   build_runner_conf:   test_runner_home:   test_runner_conf:   deploy_runner_home:   deploy_runner_conf:  services:   # gitlab-ce   gitlab-ce:     image: gitlab\/gitlab-ce:16.1.0-ce.0     shm_size: '2gb'     container_name: gitlab-ce     hostname: gitlab-ce.local     restart: always     depends_on:       - build-runner       - test-runner       - deploy-runner     volumes:       - gitlab_conf:\/etc\/gitlab       - gitlab_data:\/var\/opt\/gitlab       - gitlab_logs:\/var\/log\/gitlab     ports:       - \"127.0.0.1:22:22\"       - \"127.0.0.1:80:80\"     networks:       - gitlab_ce     deploy:       resources:         limits:           cpus: \"4\"           memory: 8G    # gitlab-build-runner   build-runner:     build: .\/     container_name: gitlab-build-runner     hostname: gitlab-build-runner.local     restart: always     volumes:       - build_runner_conf:\/etc\/gitlab-runner       - build_runner_home:\/home\/gitlab-runner       - \/var\/run\/docker.sock:\/var\/run\/docker.sock:rw     networks:       - gitlab_ce     deploy:       resources:         limits:           cpus: \"4\"           memory: 4G    # gitlab-test-runner   test-runner:     build: .\/     container_name: gitlab-test-runner     hostname: gitlab-test-runner.local     restart: always     volumes:       - test_runner_conf:\/etc\/gitlab-runner       - test_runner_home:\/home\/gitlab-runner       - \/var\/run\/docker.sock:\/var\/run\/docker.sock:rw     networks:       - gitlab_ce     deploy:       resources:         limits:           cpus: \"1\"           memory: 1G    # gitlab-deploy-runner   deploy-runner:     build: .\/     container_name: gitlab-deploy-runner     hostname: gitlab-deploy-runner.local     restart: always     volumes:       - deploy_runner_conf:\/etc\/gitlab-runner       - deploy_runner_home:\/home\/gitlab-runner       - \/var\/run\/docker.sock:\/var\/run\/docker.sock:rw     networks:       - gitlab_ce     deploy:       resources:         limits:           cpus: \"1\"           memory: 1G <\/code><\/pre>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0435\u043a\u0446\u0438\u044e deploy \u0432 \u043a\u0430\u0436\u0434\u043e\u043c<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-390450","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/390450","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=390450"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/390450\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=390450"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=390450"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=390450"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}