diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 83dd125a..5510a742 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -151,7 +151,7 @@ release_pypi: publish_docker: stage: publish - image: vstconsulting/images:tox + image: vstconsulting/images:ubuntu services: - name: 'docker:19.03-dind' alias: 'docker_service_host' diff --git a/Dockerfile b/Dockerfile index 40d810dc..3656da6b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,8 @@ RUN --mount=type=cache,target=/var/cache/apt \ git \ sudo \ sshpass \ + libpcre3 \ + libpcre3-dev \ python3.8-dev \ libldap2-dev \ libldap-2.4-2 \ @@ -53,6 +55,7 @@ RUN --mount=type=cache,target=/var/cache/apt \ mkdir -p /projects /hooks /run/openldap /etc/polemarch/hooks && \ python3.8 -m pip install /polemarch_env/dist/$(ls /polemarch_env/dist/ | grep "\.tar\.gz" | tail -1)[mysql,postgresql] && \ apt remove -y \ + libpcre3-dev \ python3.8-dev \ libldap2-dev \ libsasl2-dev \ diff --git a/autobuild.sh b/autobuild.sh index e51c2b0b..b459b99d 100755 --- a/autobuild.sh +++ b/autobuild.sh @@ -1,4 +1,3 @@ -#!/usr/bin/env bash CURRENT_VERSION=$(python3 setup.py --version | tr -d '\n') TAG=$(git tag -l | tail -1 | tr -d '\n') REGISTRY_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}" @@ -7,11 +6,11 @@ export DOCKER_BUILDKIT=1 export COMPOSE_DOCKER_CLI_BUILD=1 docker_worker (){ - docker tag ce_polemarch $1:$2 + docker tag polemarch $1:$2 docker push $1:$2 } -docker-compose build polemarch +docker-compose build polemarch | exit 1 docker login -u "${CI_REGISTRY_USER}" -p "${CI_BUILD_TOKEN}" "${CI_REGISTRY}" docker login -u "${POLEMARCH_DOCKER_USER}" -p "${POLEMARCH_DOCKER_PASSWORD}" diff --git a/doc/api_schema.yaml b/doc/api_schema.yaml index c1d71ab9..4e2ee32a 100644 --- a/doc/api_schema.yaml +++ b/doc/api_schema.yaml @@ -17,9 +17,9 @@ info: docs_url: /docs/ x-links: Request: - - url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Ask&issue%5Btitle%5D=Ask%20about%20version%201.8.5 + - url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Ask&issue%5Btitle%5D=Ask%20about%20version%202.0.0b1 name: Question - - url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Bug&issue%5Btitle%5D=Bug%20in%20version%201.8.5 + - url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Bug&issue%5Btitle%5D=Bug%20in%20version%202.0.0b1 name: Bug report - url: https://gitlab.com/vstconsulting/polemarch/issues/new?issuable_template%5D=Feature%20request&issue%5Btitle%5D= name: Feature request @@ -66,9 +66,9 @@ info: logout_url: /account/logout/ login_url: /account/login/ x-versions: - application: 1.8.5 - library: 1.8.5 - vstutils: 5.0.0b118 + application: 2.0.0b1 + library: 2.0.0b1 + vstutils: 5.0.0b122 django: 3.2.12 djangorestframework: 3.13.1 drf_yasg: 1.20.0 @@ -11969,14 +11969,13 @@ definitions: maximum: 4 Module: required: - - group - module - - args type: object properties: group: title: Group type: string + default: all minLength: 1 module: title: Module @@ -11991,7 +11990,7 @@ definitions: args: title: Arguments type: string - minLength: 1 + default: '' vars: type: object properties: @@ -12335,14 +12334,13 @@ definitions: maximum: 4 Module: required: - - group - module - - args type: object properties: group: title: Group type: string + default: all minLength: 1 module: title: Module @@ -12357,7 +12355,7 @@ definitions: args: title: Arguments type: string - minLength: 1 + default: '' vars: type: object properties: @@ -12734,14 +12732,13 @@ definitions: maximum: 4 Module: required: - - group - module - - args type: object properties: group: title: Group type: string + default: all minLength: 1 module: title: Module @@ -12756,7 +12753,7 @@ definitions: args: title: Arguments type: string - minLength: 1 + default: '' vars: type: object properties: @@ -13087,14 +13084,13 @@ definitions: maximum: 4 Module: required: - - group - module - - args type: object properties: group: title: Group type: string + default: all minLength: 1 module: title: Module @@ -13109,7 +13105,7 @@ definitions: args: title: Arguments type: string - minLength: 1 + default: '' vars: type: object properties: diff --git a/docker-compose.yml b/docker-compose.yml index f605a753..4942a96b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,25 @@ version: '3' services: + traefik: + image: traefik:2.6 + restart: unless-stopped + volumes: + - ./traefik_dynamic.yml:/traefik_dynamic.yml:ro + environment: + TRAEFIK_PROVIDERS_FILE_FILENAME: "/traefik_dynamic.yml" + TRAEFIK_PING: "true" + TRAEFIK_ENTRYPOINTS_HTTP_ADDRESS: ":80" + healthcheck: + test: [ "CMD", "traefik", "healthcheck" ] + interval: 3s + timeout: 3s + retries: 3 + ports: + - "8080:80" polemarch: + image: polemarch build: . restart: unless-stopped depends_on: @@ -16,8 +33,6 @@ services: tty: true volumes: - ./settings.ini:/etc/polemarch/settings.ini:ro - ports: - - "8080:8080" redis: image: "redis:6" @@ -40,6 +55,27 @@ services: volumes: - data-volume:/var/lib/mysql + centrifugo: + image: centrifugo/centrifugo:v3 + restart: unless-stopped + tty: true + environment: + CENTRIFUGO_TOKEN_HMAC_SECRET_KEY: "d4074fd2-607c-41b0-ab83-f2bc55fae0ec" + CENTRIFUGO_API_KEY: "a08caef0-f1ad-40de-9e59-dd2cec07e2eb" + CENTRIFUGO_ADMIN: "true" + CENTRIFUGO_ADMIN_PASSWORD: "01a18ca9-9328-4ee7-a8de-7e5b231d1df4" + CENTRIFUGO_ADMIN_SECRET: "7e91c9c1-6303-42b1-9f28-1cdfbf58dcf9" + CENTRIFUGO_HISTORY_SIZE: "10" + CENTRIFUGO_HISTORY_TTL: "300s" + CENTRIFUGO_HEALTH: "true" + CENTRIFUGO_ALLOWED_ORIGINS: "*" + healthcheck: + test: [ "CMD", "sh", "-c", "wget -nv -O - http://localhost:8000/health" ] + interval: 3s + timeout: 3s + retries: 3 + command: centrifugo + volumes: data-volume: diff --git a/frontend_src_new/.eslintrc.js b/frontend_src_new/.eslintrc.js index 1d2b8fbe..2bbbc1f3 100644 --- a/frontend_src_new/.eslintrc.js +++ b/frontend_src_new/.eslintrc.js @@ -19,6 +19,7 @@ module.exports = { 'vue/html-self-closing': ['error', { html: { void: 'any' } }], 'vue/max-attributes-per-line': 'off', 'vue/multi-word-component-names': 'off', + 'vue/one-component-per-file': 'off', }, globals: { spa: 'readonly', diff --git a/frontend_src_new/history/ExecutionTimeField.js b/frontend_src_new/history/ExecutionTimeField.js new file mode 100644 index 00000000..aad429f2 --- /dev/null +++ b/frontend_src_new/history/ExecutionTimeField.js @@ -0,0 +1,51 @@ +/** @vue/component */ +export const ExecutionTimeFieldMixin = { + data() { + return { + intervalId: null, + generatedTime: null, + }; + }, + computed: { + shouldGenerateTime() { + return this.$app.centrifugoClient && ['RUN', 'DELAY'].includes(this.data.status); + }, + value() { + if (this.shouldGenerateTime) { + return this.generatedTime; + } + return this.data[this.field.name]; + }, + }, + watch: { + shouldGenerateTime: { + immediate: true, + handler(value) { + if (value && !this.intervalId) { + this.intervalId = setInterval(() => this.updateGeneratedTime(), 1000); + } else { + clearInterval(this.intervalId); + } + }, + }, + }, + methods: { + updateGeneratedTime() { + this.generatedTime = this.$u.getTimeInUptimeFormat( + window.moment.duration(window.moment().diff(this.data.start_time)).asSeconds(), + ); + }, + }, +}; + +export class ExecutionTimeField extends spa.fields.datetime.UptimeField { + static format = 'execution-time'; + + static get mixins() { + return super.mixins.concat(ExecutionTimeFieldMixin); + } +} + +spa.signals.once('APP_CREATED', (app) => { + app.fieldsResolver.registerField('integer', ExecutionTimeField.format, ExecutionTimeField); +}); diff --git a/frontend_src_new/history/OldLinesMixin.js b/frontend_src_new/history/OldLinesMixin.js index 954b92fc..69d67912 100644 --- a/frontend_src_new/history/OldLinesMixin.js +++ b/frontend_src_new/history/OldLinesMixin.js @@ -2,6 +2,10 @@ // Old logic is used for now, code style may be bad but it is working // TODO: Probably need to rewrite it +function isSameLine(first, second) { + return first.line_number === second.line_number && first.line_gnumber === second.line_gnumber; +} + /** @vue/component */ export default { mixins: [spa.autoupdate.ComponentWithAutoUpdate], @@ -27,6 +31,10 @@ export default { * Property, that stores stdout DOM element. */ stdout_el: undefined, + /** + * Centrifuge subscription to history_lines channel + */ + subscription: null, }; }, @@ -64,20 +72,6 @@ export default { return obj; }, - /** - * Property, that return lines ready to represent - gluedLines with appropriate ansi_up CSS classes. - */ - linesHTML() { - let html = []; - - for (let key in this.gluedLines) { - if (this.gluedLines.hasOwnProperty(key)) { - html.push(spa.colors.ansiToHTML(this.gluedLines[key].text)); - } - } - - return html.join(''); - }, /** * Property, that return boolean values, that means: need to load additional lines on scroll event or not. * @return {boolean} @@ -97,6 +91,9 @@ export default { return true; }, + pk() { + return this.page.instance.getPkValue(); + }, }, watch: { @@ -116,15 +113,35 @@ export default { setTimeout(() => { $(this.stdout_el).scrollTop($(this.stdout_el).prop('scrollHeight')); }, 300); - this.startAutoUpdate(); + if (['RUN', 'DELAY'].includes(this.instance.status)) { + this.startUpdate(); + } }); }, + beforeDestroy() { + if (this.subscription) { + this.subscription.unsubscribe(); + } + }, + mounted() { this.stdout_el = $(this.$el).find('.history-stdout')[0]; }, methods: { + startUpdate() { + if (this.$app.centrifugoClient) { + this.subscription = this.$app.centrifugoClient.subscribe('history_lines', (msg) => { + if (msg.data.pk === this.pk && !this.loading) { + this.updateData(); + } + }); + } else { + this.startAutoUpdate(); + } + }, + autoAutoUpdateActionName() { return 'updateData'; }, @@ -256,20 +273,12 @@ export default { }, /** * Method, that saves only lines, that were not saved before. - * @param {array} new_lines Array with potential new lines. + * @param {array} newLines Array with potential new lines. */ - saveNewLines(new_lines = []) { - for (let index = 0; index < new_lines.length; index++) { - let new_line = new_lines[index]; - - let filtered = this.lines.filter((line) => { - if (spa.utils.deepEqual(line, new_line)) { - return line; - } - }); - - if (filtered.length == 0) { - this.lines.push(new_line); + saveNewLines(newLines = []) { + for (const newLine of newLines) { + if (!this.lines.some((line) => isSameLine(line, newLine))) { + this.lines.push(newLine); } } }, diff --git a/frontend_src_new/history/OutputLines.vue b/frontend_src_new/history/OutputLines.vue index f28238bc..b2df1f76 100644 --- a/frontend_src_new/history/OutputLines.vue +++ b/frontend_src_new/history/OutputLines.vue @@ -21,8 +21,11 @@ - -
+@@ -30,9 +33,25 @@