Compare commits

...

No commits in common. "develop" and "docs-deploy" have entirely different histories.

456 changed files with 68921 additions and 10834 deletions

View File

@ -1,206 +1,40 @@
---
kind: pipeline
type: docker
name: develop build
image_pull_secrets:
- DOCKER_AUTH
name: deploy-develop-docs-site
trigger:
branch:
- develop
services:
- name: docker
# https://hub.docker.com/r/library/docker
image: hub.docker.struchkov.dev/docker:27.1.2-dind-alpine3.20
privileged: true
volumes:
- name: dockersock
path: /var/run
volumes:
- name: m2
host:
path: /drone/volume/m2
- name: dockersock
temp: {}
- docs-deploy
steps:
- name: create jar
# https://hub.docker.com/_/maven
image: hub.docker.struchkov.dev/maven:3.9-eclipse-temurin-22-alpine
volumes:
- name: m2
path: /root/.m2/repository
commands:
- mvn -U clean package
- name: docker publish develop
image: docker.struchkov.dev/docker-buildx:latest
- name: build site
image: git.struchkov.dev/upagge/mkdocs-material-insiders:latest
environment:
DOCKER_REGISTRY_TOKEN:
from_secret: DOCKER_REGISTRY_TOKEN
DOCKER_REGISTRY_USER:
from_secret: DOCKER_REGISTRY_USER
volumes:
- name: dockersock
path: /var/run
SSH_DEPLOY_KEY:
from_secret: SSH_DEPLOY_KEY
SSH_DEPLOY_HOST:
from_secret: SSH_DEPLOY_HOST
SSH_DEPLOY_PORT:
from_secret: SSH_DEPLOY_PORT
SSH_DEPLOY_PATH:
from_secret: SSH_DEPLOY_PATH
SSH_DEPLOY_USER:
from_secret: SSH_DEPLOY_USER
commands:
- echo "$DOCKER_REGISTRY_TOKEN" | docker login docker.struchkov.dev --username $DOCKER_REGISTRY_USER --password-stdin
- docker buildx create --use
- docker buildx build -f Dockerfile-develop --push --platform linux/amd64,linux/arm64/v8 -t "docker.struchkov.dev/gitlab-notify:develop" .
---
kind: pipeline
type: docker
name: release build
- eval $(ssh-agent -s)
- mkdir -p ~/.ssh
- echo "$SSH_DEPLOY_KEY" >> ~/.ssh/id_rsa
- chmod 700 ~/.ssh
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -p $SSH_DEPLOY_PORT $SSH_DEPLOY_HOST >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
- scp -r -P $SSH_DEPLOY_PORT ./gitlab-notification $SSH_DEPLOY_USER@$SSH_DEPLOY_HOST:$SSH_DEPLOY_PATH
image_pull_secrets:
- DOCKER_AUTH
trigger:
ref:
- refs/tags/v.*.*.*
services:
- name: docker
# https://hub.docker.com/r/library/docker
image: hub.docker.struchkov.dev/docker:27.1.2-dind-alpine3.20
privileged: true
volumes:
- name: dockersock
path: /var/run
volumes:
- name: m2
host:
path: /drone/volume/m2
- name: dockersock
temp: {}
steps:
- name: create jar
image: hub.docker.struchkov.dev/maven:3.9-eclipse-temurin-22-alpine
volumes:
- name: m2
path: /root/.m2/repository
commands:
- mvn -U clean package
- name: docker publish release
image: docker.struchkov.dev/docker-buildx:latest
volumes:
- name: dockersock
path: /var/run
environment:
DOCKER_REGISTRY_TOKEN:
from_secret: DOCKER_REGISTRY_TOKEN
DOCKER_REGISTRY_USER:
from_secret: DOCKER_REGISTRY_USER
commands:
- echo "$DOCKER_REGISTRY_TOKEN" | docker login docker.struchkov.dev --username $DOCKER_REGISTRY_USER --password-stdin
- docker buildx create --use
- docker buildx build --push --platform linux/amd64,linux/arm64/v8 -t "docker.struchkov.dev/gitlab-notify:latest" -t "docker.struchkov.dev/gitlab-notify:$DRONE_TAG" .
#---
#kind: pipeline
#type: docker
#name: create-develop-docs-site
#
#trigger:
# branch:
# - develop
# - docs
#
#clone:
# disable: true
#
#steps:
#
# - name: build docs
# image: git.struchkov.dev/upagge/mkdocs-material-insiders:latest
# volumes:
# - name: mkdocs_cache
# path: ${DRONE_WORKSPACE}/documentation/ru/.cache
# environment:
# GIT_SSH:
# from_secret: GIT_SSH
# GIT_SSH_COMMAND: "ssh -i ~/.ssh/id_rsa -p 222"
# commands:
# - eval $(ssh-agent -s)
# - mkdir -p ~/.ssh
# - chmod 700 ~/.ssh
# - echo "$GIT_SSH" >> ~/.ssh/id_rsa
# - chmod 600 ~/.ssh/id_rsa
# - ssh-keyscan -p 222 git.struchkov.dev >> ~/.ssh/known_hosts
# - chmod 644 ~/.ssh/known_hosts
# - git config --global user.name "${DRONE_COMMIT_AUTHOR_NAME}"
# - git config --global user.email "${DRONE_COMMIT_AUTHOR_EMAIL}"
# - git clone ssh://git@git.struchkov.dev:222/Telegram-Bots/gitlab-notification.git .
# - git checkout $DRONE_COMMIT
# - cd documentation/ru
# - mike deploy --prefix gitlab-notification/ru --branch docs-deploy --push --update-aliases develop
#
#image_pull_secrets:
# - DOCKER_AUTH
#
#volumes:
# - name: mkdocs_cache
# host:
# path: /drone/volume/mkdocs_cache/gitlab_notification/ru
#
#---
#kind: pipeline
#type: docker
#name: create-release-docs-site
#
#trigger:
# ref:
# - refs/tags/v.*.*.*
#
#clone:
# disable: true
#
#steps:
#
# - name: build docs
# image: git.struchkov.dev/upagge/mkdocs-material-insiders:latest
# volumes:
# - name: mkdocs_cache
# path: ${DRONE_WORKSPACE}/documentation/ru/.cache
# environment:
# GIT_SSH:
# from_secret: GIT_SSH
# GIT_SSH_COMMAND: "ssh -i ~/.ssh/id_rsa -p 222"
# commands:
# - eval $(ssh-agent -s)
# - mkdir -p ~/.ssh
# - chmod 700 ~/.ssh
# - echo "$GIT_SSH" >> ~/.ssh/id_rsa
# - chmod 600 ~/.ssh/id_rsa
# - ssh-keyscan -p 222 git.struchkov.dev >> ~/.ssh/known_hosts
# - chmod 644 ~/.ssh/known_hosts
# - git config --global user.name "${DRONE_COMMIT_AUTHOR_NAME}"
# - git config --global user.email "${DRONE_COMMIT_AUTHOR_EMAIL}"
# - git clone ssh://git@git.struchkov.dev:222/Telegram-Bots/gitlab-notification.git .
# - git checkout $DRONE_COMMIT
# - cd documentation/ru
# - mike deploy --prefix gitlab-notification/ru --branch docs-deploy --push --update-aliases ${DRONE_TAG}
# - mike deploy --prefix gitlab-notification/ru --branch docs-deploy --push --update-aliases latest
#
#image_pull_secrets:
# - DOCKER_AUTH
#
#volumes:
# - name: mkdocs_cache
# host:
# path: /drone/volume/mkdocs_cache/gitlab_notification\
# drone sign --save Telegram-Bots/gitlab-notification
---
kind: signature
hmac: b0704e1ed6c75469f2197afa7de1fb6f4a96765bb00f766be8a3da6fc4a87267
hmac: e69cfd9c4c2c1a5c23907bc68bbe1cb2663194be5dd054492977f02f58e612d6
...

1
.gitattributes vendored
View File

@ -1 +0,0 @@
*.mp4 filter=lfs diff=lfs merge=lfs -text

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
custom: ["https://docs.struchkov.dev/gitlab-notification/ru/latest/support-development/"]

110
.gitignore vendored
View File

@ -1,38 +1,78 @@
HELP.md
*.class
*.log
*.ctxt
.mtj.tmp/
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
hs_err_pid*
replay_pid*
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
.classpath
.idea/
cmake-build-*/
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/
/.mvn/wrapper/
/mvnw
/mvnw.cmd
/documentation/site/
/documentation/.cache/
/documentation/ru/site/
/documentation/ru/.cache/
out/
.idea_modules/
atlassian-ide-plugin.xml
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
*~
.fuse_hidden*
.directory
.Trash-*
.nfs*
.gradle
**/build/
!src/**/build/
gradle-app.setting
!gradle-wrapper.jar
!gradle-wrapper.properties
.gradletasknamecache
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
*.stackdump
[Dd]esktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msix
*.msm
*.msp
*.lnk
.DS_Store
.AppleDouble
.LSOverride
Icon
._*
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
/documentation/

0
.nojekyll Normal file
View File

View File

@ -1,33 +0,0 @@
FROM eclipse-temurin:17 AS app-build
ENV RELEASE=17
WORKDIR /opt/build
COPY ./gitlab-app/target/gitlab-notification.jar ./application.jar
RUN java -Djarmode=layertools -jar application.jar extract
RUN $JAVA_HOME/bin/jlink \
--add-modules `jdeps --ignore-missing-deps -q -recursive --multi-release ${RELEASE} --print-module-deps -cp 'dependencies/BOOT-INF/lib/*' application.jar`,jdk.crypto.cryptoki \
--strip-java-debug-attributes \
--no-man-pages \
--no-header-files \
--compress=2 \
--output jdk
FROM debian:buster-slim
ARG BUILD_PATH=/opt/build
ENV JAVA_HOME=/opt/jdk
ENV PATH "${JAVA_HOME}/bin:${PATH}"
RUN apt update && groupadd --gid 1000 spring-app \
&& useradd --uid 1000 --gid spring-app --shell /bin/bash --create-home spring-app
USER spring-app:spring-app
WORKDIR /opt/workspace
COPY --from=app-build $BUILD_PATH/jdk $JAVA_HOME
COPY --from=app-build $BUILD_PATH/spring-boot-loader/ ./
COPY --from=app-build $BUILD_PATH/dependencies/ ./
COPY --from=app-build $BUILD_PATH/application/ ./
ENTRYPOINT ["java", "-Dfile.encoding=UTF8", "-Dconsole.encoding=UTF8", "org.springframework.boot.loader.JarLauncher"]

View File

@ -1,34 +0,0 @@
FROM eclipse-temurin:17 AS app-build
ENV RELEASE=17
WORKDIR /opt/build
COPY ./gitlab-app/target/gitlab-notification.jar ./application.jar
RUN java -Djarmode=layertools -jar application.jar extract
RUN $JAVA_HOME/bin/jlink \
--add-modules `jdeps --ignore-missing-deps -q -recursive --multi-release ${RELEASE} --print-module-deps -cp 'dependencies/BOOT-INF/lib/*':'snapshot-dependencies/BOOT-INF/lib/*' application.jar`,jdk.crypto.cryptoki \
--strip-java-debug-attributes \
--no-man-pages \
--no-header-files \
--compress=2 \
--output jdk
FROM debian:buster-slim
ARG BUILD_PATH=/opt/build
ENV JAVA_HOME=/opt/jdk
ENV PATH "${JAVA_HOME}/bin:${PATH}"
RUN apt update && groupadd --gid 1000 spring-app \
&& useradd --uid 1000 --gid spring-app --shell /bin/bash --create-home spring-app
USER spring-app:spring-app
WORKDIR /opt/workspace
COPY --from=app-build $BUILD_PATH/jdk $JAVA_HOME
COPY --from=app-build $BUILD_PATH/spring-boot-loader/ ./
COPY --from=app-build $BUILD_PATH/dependencies/ ./
COPY --from=app-build $BUILD_PATH/snapshot-dependencies/ ./
COPY --from=app-build $BUILD_PATH/application/ ./
ENTRYPOINT ["java", "-Dfile.encoding=UTF8", "-Dconsole.encoding=UTF8", "org.springframework.boot.loader.JarLauncher"]

201
LICENSE
View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 uPagge
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,23 +0,0 @@
# Уведомления GitLab в Telegram
> Документация по проекту, с описанием возможностей: https://docs.struchkov.dev/gitlab-notification
>
> Канал в Telegram, в который публикуется информация о разработке: https://t.me/gitlab_notification
Запустите своего личного GitLab бота и получайте персональные уведомления из GitLab прямо на свой аккаунт в Telegram! Это не облачное решение, бот запускается на вашей машине или вашем сервере.
Вы больше никогда не пропустите важное уведомление. Будь то новый запрос на слияние или возникновение конфликта. Больше не нужно заходить в GitLab, чтобы проверить статус сборки - с нашим приложением вы сможете оставаться в курсе дел, где бы вы ни находились.
Бота легко настроить и использовать, а быстрые действия призваны оптимизировать ваш рабочий процесс. Не ждите больше - запустите своего персонального Telegram бота, и получайте персональные уведомления о событиях в GitLab.
## Основные возможности
1. Уведомление о новых Merge Request.
2. Уведомление о возникновении конфликта в MergeRequest.
3. Уведомление о результате сборки.
4. Уведомление в тредах.
5. И многое, многое другое
## Как запустить?
Я серьезно, все подробно описано в [соответствующем разделе документации.](https://docs.struchkov.dev/gitlab-notification/ru/latest/getting-started/configuration/)

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.struchkov.bot.gitlab</groupId>
<artifactId>gitlab-bot</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>bot-context</artifactId>
<dependencies>
<dependency>
<groupId>dev.struchkov.haiti.utils</groupId>
<artifactId>haiti-utils-field-constants</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.haiti</groupId>
<artifactId>haiti-utils</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.haiti.filter</groupId>
<artifactId>haiti-filter-criteria</artifactId>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,19 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class Answer {
private final String authorName;
private final String message;
public static Answer of(@NonNull String name, @NonNull String message) {
return new Answer(name, message);
}
}

View File

@ -1,41 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.NonNull;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class ExistContainer<Entity, Key> {
protected final List<Entity> container;
protected final boolean allFound;
protected final Set<Key> idNoFound;
protected ExistContainer(List<Entity> container, boolean allFound, Set<Key> idNoFound) {
this.container = container;
this.allFound = allFound;
this.idNoFound = idNoFound;
}
public static <T, K> ExistContainer<T, K> allFind(@NonNull List<T> container) {
return new ExistContainer<>(container, true, Collections.emptySet());
}
public static <T, K> ExistContainer<T, K> notAllFind(@NonNull List<T> container, @NonNull Set<K> idNoFound) {
return new ExistContainer<>(container, false, idNoFound);
}
public List<Entity> getContainer() {
return container;
}
public boolean isAllFound() {
return allFound;
}
public Set<Key> getIdNoFound() {
return idNoFound;
}
}

View File

@ -1,17 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@AllArgsConstructor
public class IdAndStatusPr {
private Long id;
private Long twoId;
private Long projectId;
private MergeRequestState status;
}

View File

@ -1,11 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain;
/**
*
* @author upagge 14.01.2021
*/
public enum MergeRequestState {
OPENED, CLOSED, LOCKED, MERGED
}

View File

@ -1,23 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class MessageSend {
@EqualsAndHashCode.Include
private Long id;
private Long telegramId;
private String message;
}

View File

@ -1,25 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author upagge 15.01.2021
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class PersonInformation {
private String username;
private String name;
private Long id;
private String telegramId;
}

View File

@ -1,28 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* @author upagge 17.01.2021
*/
@Getter
@RequiredArgsConstructor
public enum PipelineStatus {
CREATED("\uD83C\uDD95"),
WAITING_FOR_RESOURCE("\uD83D\uDCA2"),
PREPARING("♿️"),
PENDING("⚠️"),
RUNNING("\uD83D\uDD04"),
SUCCESS(""),
FAILED(""),
CANCELED("\uD83D\uDEAB"),
SKIPPED("\uD83D\uDD18"),
MANUAL("\uD83D\uDD79"),
SCHEDULED("\uD83D\uDD52"),
NEW("\uD83C\uDD95");
private final String icon;
}

View File

@ -1,51 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.changed;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ApprovalChanged {
private Set<Person> newApproval;
private Set<Person> dontApprove;
public static Optional<ApprovalChanged> approvalChanged(List<Person> oldApproval, List<Person> newApproval) {
// Если списки одинаковы, возвращаем пустой Optional
if (Objects.equals(oldApproval, newApproval)) {
return Optional.empty();
}
// Преобразуем списки в множества для удобства вычислений
Set<Person> oldApprovalSet = new HashSet<>(oldApproval);
Set<Person> newApprovalSet = new HashSet<>(newApproval);
// Вычисляем новые одобрения: те, кто есть в новом списке, но нет в старом
final Set<Person> newApprovalSetOnly = new HashSet<>(newApprovalSet);
newApprovalSetOnly.removeAll(oldApprovalSet);
// Вычисляем тех, кто больше не одобряет: те, кто есть в старом списке, но нет в новом
final Set<Person> dontApproveSet = new HashSet<>(oldApprovalSet);
dontApproveSet.removeAll(newApprovalSet);
if (!newApprovalSetOnly.isEmpty() || !dontApproveSet.isEmpty()) {
return Optional.of(new ApprovalChanged(newApprovalSetOnly, dontApproveSet));
}
return Optional.empty();
}
}

View File

@ -1,47 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.changed;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Optional;
@Getter
@RequiredArgsConstructor
public enum AssigneeChanged {
BECOME(true),
DELETED(true),
NOT_AFFECT_USER(true),
NOT_CHANGED(false);
private final boolean changed;
public static AssigneeChanged valueOf(Long gitlabUserId, Optional<Person> oldAssignee, Optional<Person> newAssignee) {
if (oldAssignee.isEmpty() && newAssignee.isPresent() && gitlabUserId.equals(newAssignee.get().getId())) {
return AssigneeChanged.BECOME;
}
if (oldAssignee.isPresent() && newAssignee.isEmpty() && gitlabUserId.equals(oldAssignee.get().getId())) {
return AssigneeChanged.DELETED;
}
if (oldAssignee.isPresent() && newAssignee.isPresent() && !oldAssignee.get().getId().equals(newAssignee.get().getId())) {
if (gitlabUserId.equals(oldAssignee.get().getId())) {
return AssigneeChanged.DELETED;
}
if (gitlabUserId.equals(newAssignee.get().getId())) {
return AssigneeChanged.BECOME;
}
return AssigneeChanged.NOT_AFFECT_USER;
}
return AssigneeChanged.NOT_CHANGED;
}
public boolean getNewStatus(boolean oldStatus) {
return switch (this) {
case BECOME -> true;
case DELETED -> false;
case NOT_CHANGED, NOT_AFFECT_USER -> oldStatus;
};
}
}

View File

@ -1,46 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.changed;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Getter
@RequiredArgsConstructor
public enum ReviewerChanged {
BECOME(true),
DELETED(true),
NOT_AFFECT_USER(true),
NOT_CHANGED(false);
private final boolean changed;
public static ReviewerChanged valueOf(Long gitlabUserId, List<Person> oldReviewers, List<Person> newReviewers) {
final Map<Long, Person> oldMap = oldReviewers.stream().collect(Collectors.toMap(Person::getId, p -> p));
final Map<Long, Person> newMap = newReviewers.stream().collect(Collectors.toMap(Person::getId, p -> p));
if (!oldMap.keySet().equals(newMap.keySet())) {
if (oldMap.containsKey(gitlabUserId) && !newMap.containsKey(gitlabUserId)) {
return ReviewerChanged.DELETED;
}
if (!oldMap.containsKey(gitlabUserId) && newMap.containsKey(gitlabUserId)) {
return ReviewerChanged.BECOME;
}
return ReviewerChanged.NOT_AFFECT_USER;
}
return ReviewerChanged.NOT_CHANGED;
}
public boolean getNewStatus(boolean oldStatus) {
return switch (this) {
case BECOME -> true;
case DELETED -> false;
case NOT_AFFECT_USER, NOT_CHANGED -> oldStatus;
};
}
}

View File

@ -1,49 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import java.util.UUID;
/**
* Основные настройки приложения.
*
* @author upagge 16.01.2021
*/
@Entity
@Getter
@Setter
@Table(name = "app_setting")
public class AppSetting {
@Id
@Column(name = "id")
private Long id;
@Column(name = "service_key")
private UUID serviceKey = UUID.randomUUID();
@Column(name = "first_start")
private boolean firstStart;
@Column(name = "enable_notify")
private boolean enableNotify;
@Column(name = "project_owner_scan")
private boolean projectOwnerScan;
@Column(name = "project_private_scan")
private boolean projectPrivateScan;
@Enumerated(EnumType.STRING)
@Column(name = "discussion_notify_level")
private DiscussionLevel discussionNotifyLevel;
}

View File

@ -1,120 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
import java.util.Optional;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
/**
* @author upagge 11.02.2021
*/
@Getter
@Setter
@Entity
@NoArgsConstructor
@Builder(toBuilder = true)
@Table(name = "discussion")
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Discussion {
@Id
@Column(name = "id")
private String id;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumn(name = "responsible_id")
private Person responsible;
@Column(name = "resolved")
private Boolean resolved;
@Column(name = "notification")
private boolean notification;
@ManyToOne(optional = false, cascade = CascadeType.REMOVE)
@JoinTable(
name = "discussion_merge_request",
joinColumns = @JoinColumn(name = "discussion_id"),
inverseJoinColumns = @JoinColumn(name = "merge_request_id")
)
private MergeRequestForDiscussion mergeRequest;
@OneToMany(
mappedBy = "discussion",
fetch = FetchType.EAGER,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE,
CascadeType.REFRESH
}
)
private List<Note> notes;
public void setNotes(List<Note> notes) {
notes.forEach(note -> note.setDiscussion(this));
this.notes = notes;
}
public int getNoteSize() {
if (checkNotEmpty(notes)) {
return notes.size();
}
return 0;
}
public Optional<Note> getNoteByNumber(int number) {
if (checkNotEmpty(notes) && number < notes.size()) {
return Optional.of(notes.get(number));
}
return Optional.empty();
}
public Note getFirstNote() {
return this.notes.get(0);
}
public Optional<Note> getLastNote() {
if (this.notes.size() > 1) {
return Optional.ofNullable(this.notes.get(this.notes.size() - 1));
}
return Optional.empty();
}
public Optional<Note> getPrevLastNote() {
final int size = notes.size();
if (size > 2) {
return Optional.of(notes.get(size - 2));
}
return Optional.empty();
}
public Optional<Note> getLastNoteByUserId(Long personId) {
for (int i = notes.size() - 1; i >= 0; i--) {
final Note note = notes.get(i);
if (note.getAuthor().getId().equals(personId)) {
return Optional.of(note);
}
}
return Optional.empty();
}
}

View File

@ -1,143 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import dev.struchkov.haiti.utils.fieldconstants.domain.Mode;
import jakarta.persistence.CascadeType;
import jakarta.persistence.CollectionTable;
import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Сущность ПуллРеквест.
*
* @author upagge [31.01.2020]
*/
@Getter
@Setter
@Entity
@ToString(onlyExplicitlyIncluded = true)
@NoArgsConstructor
@Builder(toBuilder = true)
@Table(name = "merge_request")
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class MergeRequest {
@Id
@ToString.Include
@Column(name = "id")
@EqualsAndHashCode.Include
private Long id;
@Column(name = "two_id")
private Long twoId;
@Column(name = "project_id")
private Long projectId;
@ToString.Include
@Column(name = "title")
private String title;
@Column(name = "description")
private String description;
@Column(name = "milestone")
private String milestone;
@Enumerated(EnumType.STRING)
@Column(name = "state")
private MergeRequestState state;
@Column(name = "created_date")
private LocalDateTime createdDate;
@Column(name = "updated_date")
private LocalDateTime updatedDate;
@Column(name = "web_url")
private String webUrl;
@Column(name = "conflict")
private boolean conflict;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "author_id")
private Person author;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "assignee_id")
private Person assignee;
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE}
)
@JoinTable(
name = "merge_request_reviewer",
joinColumns = @JoinColumn(name = "merge_request_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id")
)
private List<Person> reviewers = new ArrayList<>();
@Column(name = "target_branch")
private String targetBranch;
@Column(name = "source_branch")
private String sourceBranch;
@Column(name = "notification")
private boolean notification;
@Column(name = "is_assignee")
private boolean userAssignee;
@Column(name = "is_reviewer")
private boolean userReviewer;
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE}
)
@JoinTable(
name = "merge_request_approvals",
joinColumns = @JoinColumn(name = "merge_request_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id")
)
private List<Person> approvals = new ArrayList<>();
@ElementCollection
@CollectionTable(name = "merge_request_label", joinColumns = @JoinColumn(name = "merge_request_id"))
@Column(name = "label")
private Set<String> labels = new HashSet<>();
@Column(name = "date_last_commit")
private LocalDateTime dateLastCommit;
}

View File

@ -1,51 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* @author upagge 12.09.2020
*/
@Getter
@Setter
@Entity
@Table(name = "merge_request")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class MergeRequestForDiscussion {
/**
* Идентификатор
*/
@Id
@Column(name = "id")
@EqualsAndHashCode.Include
private Long id;
@Column(name = "two_id")
private Long twoId;
@Column(name = "project_id")
private Long projectId;
@Column(name = "title")
private String title;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "author_id")
private Person author;
@Column(name = "web_url")
private String webUrl;
@Column(name = "notification")
private boolean notification;
}

View File

@ -1,72 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import static jakarta.persistence.CascadeType.MERGE;
import static jakarta.persistence.CascadeType.PERSIST;
@Getter
@Setter
@Entity
@Table(name = "note")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Note {
@Id
@Column(name = "id")
@EqualsAndHashCode.Include
private Long id;
@Column(name = "type")
private String type;
@Column(name = "body")
private String body;
@Column(name = "created_date")
private LocalDateTime created;
@Column(name = "updated_date")
private LocalDateTime updated;
@ManyToOne(cascade = {PERSIST, MERGE})
@JoinColumn(name = "author_id")
private Person author;
@Column(name = "noteable_id")
private Long noteableId;
@Column(name = "noteable_type")
private String noteableType;
@Column(name = "noteable_iid")
private Long noteableIid;
@Column(name = "web_url")
private String webUrl;
@Column(name = "resolvable")
private boolean resolvable;
@Column(name = "resolved")
private Boolean resolved;
@ManyToOne(cascade = {PERSIST, MERGE})
@JoinColumn(name = "resolved_id")
private Person resolvedBy;
@ManyToOne(optional = false)
@JoinColumn(name = "discussion_id")
private Discussion discussion;
}

View File

@ -1,40 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import dev.struchkov.haiti.utils.fieldconstants.domain.Mode;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* @author upagge 14.01.2021
*/
@Entity
@Getter
@Setter
@ToString
@Table(name = "person")
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Person {
@Id
@EqualsAndHashCode.Include
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "username")
private String userName;
@Column(name = "web_url")
private String webUrl;
}

View File

@ -1,31 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import dev.struchkov.haiti.utils.fieldconstants.domain.Mode;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Entity
@Getter
@Setter
@ToString
@Table(name = "person_telegram")
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class PersonTelegram {
@Id
@EqualsAndHashCode.Include
@Column(name = "id")
private Long id;
@Column(name = "telegram_username")
private String telegramUserName;
}

View File

@ -1,67 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
/**
* @author upagge 17.01.2021
*/
@Entity
@Getter
@Setter
@FieldNames
@NoArgsConstructor
@Table(name = "pipeline")
@Builder(toBuilder = true)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Pipeline {
@Id
@Column(name = "id")
@EqualsAndHashCode.Include
private Long id;
@Column(name = "created_date")
private LocalDateTime created;
@Column(name = "updated_date")
private LocalDateTime updated;
@Enumerated(EnumType.STRING)
@Column(name = "status")
private PipelineStatus status;
@Column(name = "ref")
private String ref;
@Column(name = "web_url")
private String webUrl;
@Column(name = "project_id")
private Long projectId;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumn(name = "person_id")
private Person person;
}

View File

@ -1,54 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
/**
* @author upagge 14.01.2021
*/
@Getter
@Setter
@Entity
@Table(name = "project")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Project {
@Id
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
@Column(name = "created_date")
private LocalDateTime createdDate;
@Column(name = "creator_id")
private Long creatorId;
@Column(name = "web_url")
private String webUrl;
@Column(name = "ssh_url_to_repo")
private String sshUrlToRepo;
@Column(name = "http_url_to_repo")
private String httpUrlToRepo;
@Column(name = "notification")
private boolean notification;
@Column(name = "processing")
private boolean processing;
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.event;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(staticName = "newDiscussion")
public class NewDiscussionEvent {
private Discussion discussion;
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.event;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(staticName = "newMergeRequest")
public class NewMergeRequestEvent {
private MergeRequest mergeRequest;
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.event;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(staticName = "newPipeline")
public class NewPipelineEvent {
private Pipeline pipeline;
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.event;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(staticName = "newProject")
public class NewProjectEvent {
private Project project;
}

View File

@ -1,20 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.event;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(staticName = "updateDiscussion")
public class UpdateDiscussionEvent {
private Discussion oldDiscussion;
private Discussion newDiscussion;
}

View File

@ -1,29 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.event;
import dev.struchkov.bot.gitlab.context.domain.changed.ApprovalChanged;
import dev.struchkov.bot.gitlab.context.domain.changed.AssigneeChanged;
import dev.struchkov.bot.gitlab.context.domain.changed.ReviewerChanged;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Optional;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(staticName = "updateMergeRequest")
public class UpdateMergeRequestEvent {
private MergeRequest oldMergeRequest;
private MergeRequest newMergeRequest;
private AssigneeChanged assigneeChanged;
private ReviewerChanged reviewerChanged;
private Optional<ApprovalChanged> optApprovalChanged;
}

View File

@ -1,20 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.event;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(staticName = "updatePipeline")
public class UpdatePipelineEvent {
private Pipeline oldPipeline;
private Pipeline newPipeline;
}

View File

@ -1,23 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.filter;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Set;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class MergeRequestFilter {
private Long assignee;
private Set<MergeRequestState> states;
}

View File

@ -1,27 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.filter;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
/**
* Объект фильтра для {@link Pipeline}.
*
* @author upagge 08.02.2021
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class PipelineFilter {
private LocalDateTime lessThanCreatedDate;
}

View File

@ -1,5 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify;
public interface GroupNotify extends Notify {
}

View File

@ -1,7 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify;
public interface Notify {
String getType();
}

View File

@ -1,5 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify;
public interface PersonalNotify extends Notify{
}

View File

@ -1,57 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.comment;
import dev.struchkov.bot.gitlab.context.domain.notify.PersonalNotify;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
@Getter
@FieldNames
public final class NewCommentPersonalNotify implements PersonalNotify {
public static final String TYPE = "NewCommentNotify";
private final String threadId;
private final String mergeRequestName;
private final String url;
private final String discussionMessage;
private final String discussionAuthor;
private final String previousMessage;
private final String previousAuthor;
private final String authorName;
private final String message;
private final int numberNotes;
@Builder
public NewCommentPersonalNotify(
String threadId,
String mergeRequestName,
String url,
String discussionMessage,
String discussionAuthor,
String previousMessage,
String previousAuthor,
String authorName,
String message,
int numberNotes
) {
this.threadId = threadId;
this.mergeRequestName = mergeRequestName;
this.url = url;
this.discussionMessage = discussionMessage;
this.discussionAuthor = discussionAuthor;
this.previousMessage = previousMessage;
this.previousAuthor = previousAuthor;
this.authorName = authorName;
this.message = message;
this.numberNotes = numberNotes;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,38 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.group.mr;
import dev.struchkov.bot.gitlab.context.domain.notify.GroupNotify;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.group.mr.ConflictMrGroupNotifyFields.CLASS_NAME;
@Getter
@FieldNames
public class ConflictMrGroupNotify implements GroupNotify {
public static final String TYPE = CLASS_NAME;
protected final String sourceBranch;
protected final String projectName;
protected final String title;
protected final String url;
protected final String milestone;
protected final String authorTelegramUsername;
@Builder
public ConflictMrGroupNotify(String sourceBranch, String projectName, String title, String url, String milestone, String authorTelegramUsername) {
this.sourceBranch = sourceBranch;
this.projectName = projectName;
this.title = title;
this.url = url;
this.milestone = milestone;
this.authorTelegramUsername = authorTelegramUsername;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,51 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.group.mr;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.domain.notify.GroupNotify;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import java.util.Map;
import static dev.struchkov.bot.gitlab.context.domain.notify.group.mr.NewMergeRequestGroupPersonalNotifyFields.CLASS_NAME;
@Getter
@FieldNames
public class NewMergeRequestGroupNotify implements GroupNotify {
public static final String TYPE = CLASS_NAME;
protected final Long mrId;
protected final String projectName;
protected final String title;
protected final String url;
protected final String milestone;
protected final String description;
protected final String author;
protected final String targetBranch;
protected final String sourceBranch;
protected final Map<Long, String> reviewerTelegramUsernames;
protected final Person assignee;
@Builder
public NewMergeRequestGroupNotify(Long mrId, String projectName, String title, String url, String milestone, String description, String author, String targetBranch, String sourceBranch, Map<Long, String> reviewerTelegramUsernames, Person assignee) {
this.mrId = mrId;
this.projectName = projectName;
this.title = title;
this.url = url;
this.milestone = milestone;
this.description = description;
this.author = author;
this.targetBranch = targetBranch;
this.sourceBranch = sourceBranch;
this.reviewerTelegramUsernames = reviewerTelegramUsernames;
this.assignee = assignee;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,41 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.group.mr;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.domain.notify.GroupNotify;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
@Getter
@FieldNames
public class NoReviewerGroupNotify implements GroupNotify {
public static final String TYPE = "NoReviewersGroupNotify";
protected final String projectName;
protected final String title;
protected final String url;
protected final String milestone;
protected final String targetBranch;
protected final String sourceBranch;
protected final Person assignee;
protected final String ownerTelegramUsername;
@Builder
public NoReviewerGroupNotify(String projectName, String title, String url, String milestone, String targetBranch, String sourceBranch, Person assignee, String ownerTelegramUsername) {
this.projectName = projectName;
this.title = title;
this.url = url;
this.milestone = milestone;
this.targetBranch = targetBranch;
this.sourceBranch = sourceBranch;
this.assignee = assignee;
this.ownerTelegramUsername = ownerTelegramUsername;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,39 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.group.pipeline;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.notify.GroupNotify;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.group.pipeline.PipelineGroupNotifyFields.CLASS_NAME;
@Getter
@FieldNames
public class PipelineGroupNotify implements GroupNotify {
public static final String TYPE = CLASS_NAME;
private final String projectName;
private final String refName;
private final PipelineStatus oldStatus;
private final PipelineStatus newStatus;
private final String webUrl;
private final String ownerTelegramUsername;
@Builder
public PipelineGroupNotify(String projectName, String refName, PipelineStatus oldStatus, PipelineStatus newStatus, String webUrl, String ownerTelegramUsername) {
this.projectName = projectName;
this.refName = refName;
this.oldStatus = oldStatus;
this.newStatus = newStatus;
this.webUrl = webUrl;
this.ownerTelegramUsername = ownerTelegramUsername;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,7 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.level;
public enum DiscussionLevel {
WITHOUT_NOTIFY, NOTIFY_WITHOUT_CONTEXT, NOTIFY_WITH_CONTEXT
}

View File

@ -1,42 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import java.util.Set;
import static dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ApprovalChangedMrPersonalNotifyFields.CLASS_NAME;
@Getter
@FieldNames
public class ApprovalChangedMrPersonalNotify extends MrPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final Set<Person> newApproval;
private final Set<Person> dontApproval;
@Builder
public ApprovalChangedMrPersonalNotify(
Long mrId,
String projectName,
String title,
String url,
String milestone,
Set<Person> newApproval,
Set<Person> dontApproval
) {
super(mrId, projectName, title, url, milestone);
this.newApproval = newApproval;
this.dontApproval = dontApproval;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,35 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictMrPersonalNotifyFields.CLASS_NAME;
@Getter
@FieldNames
public class ConflictMrPersonalNotify extends MrPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final String sourceBranch;
@Builder
private ConflictMrPersonalNotify(
Long mrId,
String name,
String url,
String projectKey,
String sourceBranch,
String milestone
) {
super(mrId, projectKey, name, url, milestone);
this.sourceBranch = sourceBranch;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,35 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictResolveMrPersonalNotifyFields.CLASS_NAME;
@Getter
@FieldNames
public class ConflictResolveMrPersonalNotify extends MrPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final String sourceBranch;
@Builder
private ConflictResolveMrPersonalNotify(
Long mrId,
String name,
String url,
String projectKey,
String sourceBranch,
String milestone
) {
super(mrId, projectKey, name, url, milestone);
this.sourceBranch = sourceBranch;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,29 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.bot.gitlab.context.domain.notify.PersonalNotify;
import lombok.Getter;
@Getter
public abstract class MrPersonalNotify implements PersonalNotify {
protected final Long mrId;
protected final String projectName;
protected final String title;
protected final String url;
protected final String milestone;
protected MrPersonalNotify(
Long mrId,
String projectName,
String title,
String url,
String milestone
) {
this.mrId = mrId;
this.projectName = projectName;
this.title = title;
this.url = url;
this.milestone = milestone;
}
}

View File

@ -1,61 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
import java.util.List;
import java.util.Set;
import static dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForAssigneeFields.CLASS_NAME;
@Getter
@FieldNames
public class NewMrForAssignee extends NewMrPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final List<String> reviewers;
private final String oldAssigneeName;
private final String newAssigneeName;
@Builder
private NewMrForAssignee(
Long mrId,
String title,
String url,
String description,
String author,
String projectName,
String targetBranch,
String sourceBranch,
Set<String> labels,
@Singular List<String> reviewers,
String oldAssigneeName,
String newAssigneeName,
String milestone
) {
super(
mrId,
title,
url,
description,
author,
projectName,
targetBranch,
sourceBranch,
labels,
milestone
);
this.reviewers = reviewers;
this.oldAssigneeName = oldAssigneeName;
this.newAssigneeName = newAssigneeName;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,53 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import java.util.Set;
import static dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForReviewFields.CLASS_NAME;
@Getter
@FieldNames
public class NewMrForReview extends NewMrPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final String assignee;
@Builder
private NewMrForReview(
Long mrId,
String title,
String url,
String description,
String author,
String projectName,
String targetBranch,
String sourceBranch,
Set<String> labels,
String assignee,
String milestone
) {
super(
mrId,
title,
url,
description,
author,
projectName,
targetBranch,
sourceBranch,
labels,
milestone
);
this.assignee = assignee;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,36 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import lombok.Getter;
import java.util.Set;
@Getter
public abstract class NewMrPersonalNotify extends MrPersonalNotify {
protected final String description;
protected final String author;
protected final String targetBranch;
protected final String sourceBranch;
protected final Set<String> labels;
protected NewMrPersonalNotify(
Long mrId,
String title,
String url,
String description,
String author,
String projectName,
String targetBranch,
String sourceBranch,
Set<String> labels,
String milestone
) {
super(mrId, projectName, title, url, milestone);
this.description = description;
this.author = author;
this.targetBranch = targetBranch;
this.sourceBranch = sourceBranch;
this.labels = labels;
}
}

View File

@ -1,39 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.StatusMrPersonalNotifyFields.CLASS_NAME;
@Getter
@FieldNames
public class StatusMrPersonalNotify extends MrPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final MergeRequestState oldStatus;
private final MergeRequestState newStatus;
@Builder
private StatusMrPersonalNotify(
Long mrId,
String name,
String url,
String projectName,
MergeRequestState oldStatus,
MergeRequestState newStatus,
String milestone
) {
super(mrId, projectName, name, url, milestone);
this.oldStatus = oldStatus;
this.newStatus = newStatus;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,50 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.UpdateMrPersonalNotifyFields.CLASS_NAME;
@Getter
@FieldNames
public class UpdateMrPersonalNotify extends MrPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final String author;
private final Long allTasks;
private final Long allResolvedTasks;
private final Long personTasks;
private final Long personResolvedTasks;
private final String comment;
@Builder
private UpdateMrPersonalNotify(
Long mrId,
String name,
String url,
String author,
String projectName,
Long allTasks,
Long allResolvedTasks,
Long personTasks,
Long personResolvedTasks,
String comment,
String milestone
) {
super(mrId, projectName, name, url, milestone);
this.author = author;
this.allTasks = allTasks;
this.allResolvedTasks = allResolvedTasks;
this.personTasks = personTasks;
this.personResolvedTasks = personResolvedTasks;
this.comment = comment;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,47 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.pipeline;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.notify.PersonalNotify;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.pipeline.PipelinePersonalNotifyFields.CLASS_NAME;
/**
* @author upagge 17.01.2021
*/
//TODO [16.12.2022|uPagge]: Нужно реализовать заполнение projectName
@Getter
@FieldNames
public final class PipelinePersonalNotify implements PersonalNotify {
public static final String TYPE = CLASS_NAME;
private final String projectName;
private final String refName;
private final PipelineStatus oldStatus;
private final PipelineStatus newStatus;
private final String webUrl;
@Builder
public PipelinePersonalNotify(
String projectName,
String refName,
PipelineStatus oldStatus,
PipelineStatus newStatus,
String webUrl
) {
this.projectName = projectName;
this.refName = refName;
this.oldStatus = oldStatus;
this.newStatus = newStatus;
this.webUrl = webUrl;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,51 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.project;
import dev.struchkov.bot.gitlab.context.domain.notify.PersonalNotify;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.project.NewProjectPersonalNotifyFields.CLASS_NAME;
/**
* @author upagge 15.01.2021
*/
@Getter
@FieldNames
public final class NewProjectPersonalNotify implements PersonalNotify {
public static final String TYPE = CLASS_NAME;
private final Long projectId;
private final String projectName;
private final String projectUrl;
private final String projectDescription;
private final String authorName;
private final String sshUrlToRepo;
private final String httpUrlToRepo;
@Builder
public NewProjectPersonalNotify(
Long projectId,
String projectName,
String projectUrl,
String projectDescription,
String authorName,
String sshUrlToRepo,
String httpUrlToRepo
) {
this.projectId = projectId;
this.projectName = projectName;
this.projectUrl = projectUrl;
this.projectDescription = projectDescription;
this.authorName = authorName;
this.sshUrlToRepo = sshUrlToRepo;
this.httpUrlToRepo = httpUrlToRepo;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,44 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.task;
import dev.struchkov.haiti.utils.container.Pair;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
import java.util.List;
import static dev.struchkov.bot.gitlab.context.domain.notify.task.DiscussionNewPersonalNotifyFields.CLASS_NAME;
/**
* @author upagge 10.09.2020
*/
@Getter
@FieldNames
public class DiscussionNewPersonalNotify extends ThreadPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final String threadId;
private final List<Pair<String, String>> notes;
@Builder
public DiscussionNewPersonalNotify(
String threadId,
String mergeRequestName,
String authorName,
String url,
String discussionMessage,
@Singular List<Pair<String, String>> notes
) {
super(mergeRequestName, authorName, url, discussionMessage);
this.threadId = threadId;
this.notes = notes;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,46 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.task;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.bot.gitlab.context.domain.notify.task.ThreadClosePersonalNotifyFields.CLASS_NAME;
/**
* @author upagge 10.09.2020
*/
@Getter
@FieldNames
public class ThreadClosePersonalNotify extends ThreadPersonalNotify {
public static final String TYPE = CLASS_NAME;
private final Long personTasks;
private final Long personResolvedTasks;
private final String authorLastNote;
private final String messageLastNote;
@Builder
protected ThreadClosePersonalNotify(
String mergeRequestName,
String authorName,
String url,
String messageTask,
Long personTasks,
Long personResolvedTasks,
String authorLastNote,
String messageLastNote
) {
super(mergeRequestName, authorName, url, messageTask);
this.personTasks = personTasks;
this.personResolvedTasks = personResolvedTasks;
this.authorLastNote = authorLastNote;
this.messageLastNote = messageLastNote;
}
@Override
public String getType() {
return TYPE;
}
}

View File

@ -1,26 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.task;
import dev.struchkov.bot.gitlab.context.domain.notify.PersonalNotify;
import lombok.Getter;
@Getter
public abstract class ThreadPersonalNotify implements PersonalNotify {
protected final String mergeRequestName;
protected final String authorName;
protected final String url;
protected final String messageTask;
protected ThreadPersonalNotify(
String mergeRequestName,
String authorName,
String url,
String messageTask
) {
this.mergeRequestName = mergeRequestName;
this.authorName = authorName;
this.url = url;
this.messageTask = messageTask;
}
}

View File

@ -1,17 +0,0 @@
package dev.struchkov.bot.gitlab.context.prop;
import lombok.Getter;
import lombok.Setter;
/**
* Основные настройки приложения.
*
* @author upagge 11.10.2020
*/
@Getter
@Setter
public class AppProperty {
private String version;
}

View File

@ -1,15 +0,0 @@
package dev.struchkov.bot.gitlab.context.prop;
import lombok.Getter;
import lombok.Setter;
import java.util.Optional;
@Getter
@Setter
public class GroupNotifyProperty {
private Optional<String> chatId;
private Optional<Integer> threadId;
}

View File

@ -1,16 +0,0 @@
package dev.struchkov.bot.gitlab.context.prop;
import lombok.Getter;
import lombok.Setter;
/**
* @author upagge 15.01.2021
*/
@Getter
@Setter
public class PersonProperty {
private String telegramId;
}

View File

@ -1,15 +0,0 @@
package dev.struchkov.bot.gitlab.context.repository;
import dev.struchkov.bot.gitlab.context.domain.entity.AppSetting;
import java.util.Optional;
/**
* @author upagge 16.01.2021
*/
public interface AppSettingRepository {
AppSetting save(AppSetting appSetting);
Optional<AppSetting> findById(Long key);
}

View File

@ -1,35 +0,0 @@
package dev.struchkov.bot.gitlab.context.repository;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* @author upagge 11.02.2021
*/
public interface DiscussionRepository {
/**
* Вернуть все дискусии для MR
*/
List<Discussion> findAllByMergeRequestId(Long mergeRequestId);
Discussion save(Discussion discussion);
Optional<Discussion> findById(String discussionId);
List<Discussion> findAll();
List<Discussion> findAllById(Set<String> discussionIds);
Set<String> findAllIds();
void deleteById(String id);
void cleanOld();
void notification(boolean enable, String discussionId);
}

View File

@ -1,35 +0,0 @@
package dev.struchkov.bot.gitlab.context.repository;
import dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
import lombok.NonNull;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public interface MergeRequestRepository {
Set<IdAndStatusPr> findAllIdByStateIn(@NonNull Set<MergeRequestState> states);
MergeRequest save(MergeRequest mergeRequest);
Optional<MergeRequest> findById(Long mergeRequestId);
List<MergeRequestForDiscussion> findAllForDiscussion();
List<MergeRequest> findAllById(Set<Long> mergeRequestIds);
List<MergeRequest> findAllByReviewerId(Long personId);
void deleteByStates(Set<MergeRequestState> states);
Set<Long> findAllIds();
void notification(boolean enable, Long mrId);
void notificationByProjectId(boolean enable, Set<Long> projectIds);
}

View File

@ -1,20 +0,0 @@
package dev.struchkov.bot.gitlab.context.repository;
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Optional;
/**
* @author upagge 08.09.2020
*/
public interface NoteRepository {
List<Note> findAllByResponsibleIdAndResolved(Long userId, boolean resolved);
Page<Note> findAllByResolved(boolean resolved, Pageable pagination);
Optional<Note> findById(Long noteId);
}

View File

@ -1,25 +0,0 @@
package dev.struchkov.bot.gitlab.context.repository;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.domain.entity.PersonTelegram;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* @author upagge 15.01.2021
*/
public interface PersonRepository {
Person save(Person person);
Optional<Person> findById(Long personId);
List<Person> findAllById(Set<Long> personIds);
Optional<PersonTelegram> findTelegramInfoById(Long personId);
List<PersonTelegram> findAllTelegramInfoByIds(Set<Long> personIds);
}

View File

@ -1,28 +0,0 @@
package dev.struchkov.bot.gitlab.context.repository;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* @author upagge 17.01.2021
*/
public interface PipelineRepository {
Pipeline save(Pipeline pipeline);
Optional<Pipeline> findById(Long pipelineId);
List<Pipeline> findAllByStatuses(Set<PipelineStatus> statuses);
List<Pipeline> findAllById(Set<Long> pipelineIds);
void deleteByCreatedBefore(LocalDateTime date);
Set<Long> findAllIds();
}

View File

@ -1,36 +0,0 @@
package dev.struchkov.bot.gitlab.context.repository;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* @author upagge 14.01.2021
*/
public interface ProjectRepository {
Project save(Project project);
Optional<Project> findById(Long projectId);
List<Project> findAllById(Set<Long> projectIds);
boolean existById(Long projectId);
Page<Project> findAllById(Pageable pagination);
Set<Long> findAllIdByProcessingEnable();
Optional<String> findProjectNameById(Long projectId);
Set<Long> findAllIds();
void notification(boolean enable, Set<Long> projectIds);
void processing(boolean enable, Set<Long> projectIds);
}

View File

@ -1,46 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
import java.util.UUID;
/**
* Сервис отвечает за пользовательские настройки приложения.
*
* @author upagge 16.01.2021
*/
public interface AppSettingService {
/**
* Метод позволяет проверить запускается ли приложение впервые.
*
* @return true - если это первый запуск
*/
boolean isFirstStart();
/**
* Метод отмечает, что приложение было запущено.
*
* @see AppSettingService#isFirstStart()
*/
void disableFirstStart();
boolean isEnableAllNotify();
void turnOnAllNotify();
void privateProjectScan(boolean enable);
void ownerProjectScan(boolean enable);
boolean isOwnerProjectScan();
boolean isPrivateProjectScan();
DiscussionLevel getLevelDiscussionNotify();
void setDiscussionLevel(DiscussionLevel level);
UUID getServiceKey();
}

View File

@ -1,48 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import lombok.NonNull;
import java.util.List;
import java.util.Set;
/**
* @author upagge 11.02.2021
*/
public interface DiscussionService {
Discussion create(@NonNull Discussion discussion);
Discussion update(@NonNull Discussion discussion);
List<Discussion> updateAll(@NonNull List<Discussion> discussions);
/**
* Метод отправляющий коментарий в дискуссию.
*
* @param discussionId Идентификатор дискуссии
* @param text Текст комментария
*/
void answer(@NonNull String discussionId, @NonNull String text);
/**
* Получить все дискусси для MR.
*/
List<Discussion> getAllByMergeRequestId(@NonNull Long mergeRequestId);
ExistContainer<Discussion, String> existsById(@NonNull Set<String> discussionIds);
List<Discussion> createAll(@NonNull List<Discussion> newDiscussions);
List<Discussion> getAll();
Set<String> getAllIds();
void deleteById(@NonNull String discussionId);
void cleanOld();
void notification(boolean enable, String discussionId);
}

View File

@ -1,45 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
import lombok.NonNull;
import java.util.List;
import java.util.Set;
public interface MergeRequestsService {
MergeRequest create(@NonNull MergeRequest mergeRequest);
MergeRequest update(@NonNull MergeRequest mergeRequest);
List<MergeRequest> updateAll(@NonNull List<MergeRequest> mergeRequests);
/**
* Получить все идентификаторы вместе со статусами.
*
* @param statuses Статусы ПРов
* @return Объект, содержащий идентификатор и статус ПР
*/
Set<IdAndStatusPr> getAllId(Set<MergeRequestState> statuses);
List<MergeRequestForDiscussion> getAllForDiscussion();
ExistContainer<MergeRequest, Long> existsById(@NonNull Set<Long> mergeRequestIds);
List<MergeRequest> createAll(List<MergeRequest> newMergeRequests);
List<MergeRequest> getAllByReviewerId(@NonNull Long personId);
void cleanOld();
Set<Long> getAllIds();
void notification(boolean enable, @NonNull Long mrId);
void notificationByProjectId(boolean enable, @NonNull Set<Long> projectIds);
}

View File

@ -1,13 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.notify.GroupNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.PersonalNotify;
import lombok.NonNull;
public interface MessageSendService {
void send(@NonNull PersonalNotify notify);
void send(@NonNull GroupNotify notify);
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
import lombok.NonNull;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface NoteService {
List<Note> getAllPersonTask(@NonNull Long userId, boolean resolved);
//TODO [28.01.2022]: Решить нужно ли оставлять
Page<Note> getAllByResolved(boolean resolved, @NonNull Pageable pagination);
Note getByIdOrThrow(@NonNull Long noteId);
}

View File

@ -1,18 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.notify.GroupNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.PersonalNotify;
/**
* Сервис по работе с изменениями в битбакете.
*
* @author upagge
* @see PersonalNotify
*/
public interface NotifyService {
<T extends PersonalNotify> void send(T notify);
<T extends GroupNotify> void send(T notify);
}

View File

@ -1,29 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import lombok.NonNull;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
* @author upagge 15.01.2021
*/
public interface PersonService {
Person create(@NonNull Person person);
Person getByIdOrThrown(@NonNull Long personId);
ExistContainer<Person, Long> existsById(Set<Long> personIds);
List<Person> createAll(List<Person> newPersons);
Optional<String> getTelegramUsernamesByPersonIds(Long personId);
Map<Long, String> getTelegramUsernamesByPersonIds(Set<Long> personIds);
}

View File

@ -1,34 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import lombok.NonNull;
import java.util.List;
import java.util.Set;
/**
* Сервис для работы с пайплайнами
*
* @author upagge 17.01.2021
*/
public interface PipelineService {
Pipeline create(@NonNull Pipeline pipeline);
List<Pipeline> createAll(@NonNull List<Pipeline> newPipelines);
Pipeline update(@NonNull Pipeline pipeline);
List<Pipeline> updateAll(@NonNull List<Pipeline> pipelines);
List<Pipeline> getAllByStatuses(@NonNull Set<PipelineStatus> statuses);
ExistContainer<Pipeline, Long> existsById(@NonNull Set<Long> pipelineIds);
void cleanOld();
Set<Long> getAllIds();
}

View File

@ -1,38 +0,0 @@
package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import lombok.NonNull;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* @author upagge 14.01.2021
*/
public interface ProjectService {
Project create(@NonNull Project project, boolean sendNotify);
Project update(@NonNull Project project);
Project getByIdOrThrow(@NonNull Long projectId);
List<Project> createAll(List<Project> newProjects);
boolean existsById(Long projectId);
ExistContainer<Project, Long> existsById(Set<Long> projectIds);
Set<Long> getAllIdByProcessingEnable();
Optional<String> getProjectNameById(Long projectId);
Set<Long> getAllIds();
void notification(boolean enable, Set<Long> projectIds);
void processing(boolean enable, Set<Long> projectIds);
}

View File

@ -1,42 +0,0 @@
package dev.struchkov.bot.gitlab.context.utils;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
public class Icons {
public static final String HR = "\n-- -- -- -- --\n";
public static final String FUN = "\uD83C\uDF89";
public static final String VIEW = "\uD83D\uDC40";
public static final String TREE = "\uD83C\uDF33";
public static final String AUTHOR = "\uD83D\uDC68\u200D\uD83D\uDCBB";
public static final String UPDATE = "\uD83D\uDD04";
public static final String COMMENT = "\uD83D\uDCAC";
public static final String THREAD = "\uD83E\uDDF5";
public static final String ARROW = "";
public static final String DANGEROUS = "⚠️";
public static final String GREEN_CIRCLE = "\uD83D\uDFE2";
public static final String PEN = "✏️";
public static final String ASSIGNEE = "\uD83C\uDFA9";
public static final String APPROVAL = "\uD83D\uDC4D";
public static final String BUILD = "⚙️";
public static final String LINK = "\uD83D\uDD17";
public static final String REVIEWER = "\uD83D\uDD0E";
public static final String MILESTONE = "\uD83C\uDFAF";
public static final String PROJECT = "\uD83C\uDFD7";
public static final String DISABLE_NOTIFY = "\uD83D\uDD15";
public static final String YES = "";
public static final String NO = "";
public static final String NOTIFY = "\uD83D\uDD14";
public static final String GOOD = "\uD83D\uDC4D";
private Icons() {
utilityClass();
}
public static String link(String title, String url) {
return "[" + escapeMarkdown(title) + "](" + url + ")";
}
}

View File

@ -1,94 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.struchkov.bot.gitlab</groupId>
<artifactId>gitlab-bot</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>bot-core</artifactId>
<dependencies>
<dependency>
<groupId>dev.struchkov.haiti.filter</groupId>
<artifactId>haiti-filter-criteria</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.bot.gitlab</groupId>
<artifactId>bot-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>dev.struchkov.sdk.gitlab</groupId>
<artifactId>gitlab-sdk-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>4.0.2</version>
</dependency>
</dependencies>
</project>

View File

@ -1,31 +0,0 @@
package dev.struchkov.bot.gitlab.core.convert;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import dev.struchkov.sdk.gitlab.schema.note.DiscussionJson;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* @author upagge 11.02.2021
*/
@Component
@RequiredArgsConstructor
public class DiscussionJsonConverter implements Converter<DiscussionJson, Discussion> {
private final NoteJsonConvert noteJsonConvert;
@Override
public Discussion convert(DiscussionJson source) {
final Discussion discussion = new Discussion();
discussion.setId(source.getId());
discussion.setNotes(
source.getNotes().stream()
.filter(noteJson -> !noteJson.isSystem())
.map(noteJsonConvert::convert)
.toList()
);
return discussion;
}
}

View File

@ -1,87 +0,0 @@
package dev.struchkov.bot.gitlab.core.convert;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.sdk.gitlab.schema.common.PersonJson;
import dev.struchkov.sdk.gitlab.schema.mergerequest.MergeRequestJson;
import dev.struchkov.sdk.gitlab.schema.mergerequest.MergeRequestStateJson;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* @author upagge 15.01.2021
*/
@Component
@RequiredArgsConstructor
public class MergeRequestJsonConverter implements Converter<MergeRequestJson, MergeRequest> {
private final PersonJsonConverter convertPerson;
@Override
public MergeRequest convert(MergeRequestJson source) {
final MergeRequest mergeRequest = new MergeRequest();
mergeRequest.setConflict(source.isConflicts());
mergeRequest.setTitle(source.getTitle());
mergeRequest.setCreatedDate(source.getCreatedDate());
mergeRequest.setDescription(source.getDescription());
mergeRequest.setId(source.getId());
mergeRequest.setTwoId(source.getTwoId());
mergeRequest.setUpdatedDate(source.getUpdatedDate());
mergeRequest.setState(convertState(source.getState()));
mergeRequest.setProjectId(source.getProjectId());
mergeRequest.setWebUrl(source.getWebUrl());
convertLabels(mergeRequest, source.getLabels());
convertReviewers(mergeRequest, source.getReviewers());
if (checkNotNull(source.getMilestone())) {
mergeRequest.setMilestone(source.getMilestone().getTitle());
}
if (checkNotNull(source.getAssignee())) {
mergeRequest.setAssignee(convertPerson.convert(source.getAssignee()));
}
mergeRequest.setAuthor(convertPerson.convert(source.getAuthor()));
mergeRequest.setSourceBranch(source.getSourceBranch());
mergeRequest.setTargetBranch(source.getTargetBranch());
return mergeRequest;
}
private void convertReviewers(MergeRequest mergeRequest, List<PersonJson> jsonReviewers) {
if (checkNotEmpty(jsonReviewers)) {
final List<Person> reviewers = jsonReviewers.stream()
.map(convertPerson::convert)
.toList();
mergeRequest.setReviewers(reviewers);
}
}
private static void convertLabels(MergeRequest mergeRequest, Set<String> source) {
if (checkNotEmpty(source)) {
final Set<String> labels = source.stream()
.map(label -> label.replace("-", "_"))
.collect(Collectors.toSet());
mergeRequest.setLabels(labels);
}
}
private MergeRequestState convertState(MergeRequestStateJson state) {
return switch (state) {
case CLOSED -> MergeRequestState.CLOSED;
case LOCKED -> MergeRequestState.LOCKED;
case MERGED -> MergeRequestState.MERGED;
case OPENED -> MergeRequestState.OPENED;
};
}
}

View File

@ -1,38 +0,0 @@
package dev.struchkov.bot.gitlab.core.convert;
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
import dev.struchkov.sdk.gitlab.schema.note.NoteJson;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* @author upagge 12.09.2020
*/
@Component
@RequiredArgsConstructor
public class NoteJsonConvert implements Converter<NoteJson, Note> {
private final PersonJsonConverter personConverter;
@Override
public Note convert(NoteJson source) {
final Note note = new Note();
note.setAuthor(personConverter.convert(source.getAuthor()));
note.setId(source.getId());
note.setBody(source.getBody());
note.setType(source.getType());
note.setNoteableType(source.getNoteableType());
note.setCreated(source.getCreated());
note.setUpdated(source.getUpdated());
note.setNoteableId(source.getNoteableId());
note.setNoteableIid(source.getNoteableIid());
note.setResolved(source.getResolved());
note.setResolvable(source.isResolvable());
if (source.getResolvedBy() != null) {
note.setResolvedBy(personConverter.convert(source.getResolvedBy()));
}
return note;
}
}

View File

@ -1,24 +0,0 @@
package dev.struchkov.bot.gitlab.core.convert;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.sdk.gitlab.schema.common.PersonJson;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* @author upagge 15.01.2021
*/
@Component
public class PersonJsonConverter implements Converter<PersonJson, Person> {
@Override
public Person convert(PersonJson source) {
final Person person = new Person();
person.setId(source.getId());
person.setName(source.getName());
person.setUserName(source.getUsername());
person.setWebUrl(source.getWebUrl());
return person;
}
}

View File

@ -1,63 +0,0 @@
package dev.struchkov.bot.gitlab.core.convert;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import dev.struchkov.sdk.gitlab.schema.pipeline.PipelineJson;
import dev.struchkov.sdk.gitlab.schema.pipeline.PipelineStatusJson;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CANCELED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CREATED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.FAILED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.MANUAL;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.PENDING;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.PREPARING;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.RUNNING;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SCHEDULED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SKIPPED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SUCCESS;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.WAITING_FOR_RESOURCE;
/**
* @author upagge 17.01.2021
*/
@Component
@RequiredArgsConstructor
public class PipelineJsonConverter implements Converter<PipelineJson, Pipeline> {
private final PersonJsonConverter convertPerson;
@Override
public Pipeline convert(PipelineJson source) {
final Pipeline pipeline = new Pipeline();
pipeline.setId(source.getId());
pipeline.setCreated(source.getCreated());
pipeline.setUpdated(source.getUpdated());
pipeline.setRef(source.getRef());
pipeline.setWebUrl(source.getWebUrl());
pipeline.setStatus(convertStatus(source.getStatus()));
pipeline.setPerson(convertPerson.convert(source.getUser()));
pipeline.setProjectId(source.getProjectId());
return pipeline;
}
private PipelineStatus convertStatus(PipelineStatusJson status) {
return switch (status) {
case SKIPPED -> SKIPPED;
case CANCELED -> CANCELED;
case SUCCESS -> SUCCESS;
case MANUAL -> MANUAL;
case CREATED -> CREATED;
case PENDING -> PENDING;
case RUNNING -> RUNNING;
case PREPARING -> PREPARING;
case SCHEDULED -> SCHEDULED;
case WAITING_FOR_RESOURCE -> WAITING_FOR_RESOURCE;
default -> FAILED;
};
}
}

View File

@ -1,30 +0,0 @@
package dev.struchkov.bot.gitlab.core.convert;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import dev.struchkov.sdk.gitlab.schema.repository.ProjectJson;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* @author upagge 14.01.2021
*/
@Component
@RequiredArgsConstructor
public class ProjectJsonConverter implements Converter<ProjectJson, Project> {
@Override
public Project convert(ProjectJson source) {
final Project project = new Project();
project.setId(source.getId());
project.setCreatedDate(source.getCreatedDate());
project.setCreatorId(source.getCreatorId());
project.setDescription(source.getDescription());
project.setName(source.getName());
project.setWebUrl(source.getWebUrl());
project.setHttpUrlToRepo(source.getHttpUrlToRepo());
project.setSshUrlToRepo(source.getSshUrlToRepo());
return project;
}
}

View File

@ -1,265 +0,0 @@
package dev.struchkov.bot.gitlab.core.handler;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
import dev.struchkov.bot.gitlab.context.domain.event.NewDiscussionEvent;
import dev.struchkov.bot.gitlab.context.domain.event.UpdateDiscussionEvent;
import dev.struchkov.bot.gitlab.context.domain.notify.comment.NewCommentPersonalNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
import dev.struchkov.bot.gitlab.context.domain.notify.task.DiscussionNewPersonalNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.task.ThreadClosePersonalNotify;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
import dev.struchkov.bot.gitlab.context.service.NotifyService;
import dev.struchkov.haiti.utils.container.Pair;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.NOTIFY_WITH_CONTEXT;
import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.WITHOUT_NOTIFY;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Checker.checkNull;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
@Component
@RequiredArgsConstructor
public class DiscussionHandler {
protected static final Pattern PATTERN = Pattern.compile("@[\\w]+");
private final PersonInformation personInformation;
private final AppSettingService settingService;
private final DiscussionService discussionService;
private final NotifyService notifyService;
@EventListener
public void newDiscussionEvent(NewDiscussionEvent event) {
final Discussion discussion = event.getDiscussion();
final List<Note> notes = discussion.getNotes();
if (isNeedNotifyNewNote(discussion)) {
notifyNewThread(discussion);
} else {
notes.forEach(note -> notifyAboutPersonalAnswer(discussion, note));
}
}
@EventListener
public void updateDiscussionHandle(UpdateDiscussionEvent event) {
final Discussion oldDiscussion = event.getOldDiscussion();
final Discussion newDiscussion = event.getNewDiscussion();
if (oldDiscussion.isNotification()) {
final Map<Long, Note> oldNoteMap = oldDiscussion
.getNotes().stream()
.collect(Collectors.toMap(Note::getId, n -> n));
// Пользователь участвовал в обсуждении
final boolean userParticipatedInDiscussion = oldDiscussion.getNotes().stream()
.anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId()));
final Note threadFirstNote = newDiscussion.getFirstNote();
if (TRUE.equals(newDiscussion.getResolved())) {
notifyAboutCloseThread(threadFirstNote, oldNoteMap.get(threadFirstNote.getId()), newDiscussion.getLastNote());
}
for (Note newNote : newDiscussion.getNotes()) {
final Long newNoteId = newNote.getId();
if (!oldNoteMap.containsKey(newNoteId)) {
if (userParticipatedInDiscussion) {
notifyAboutNewAnswer(newDiscussion, newNote);
} else {
notifyAboutPersonalAnswer(newDiscussion, newNote);
}
}
}
}
}
/**
* <p>Уведомляет пользователя, если появился новый комментарий</p>
*/
private void notifyNewThread(Discussion discussion) {
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
if (!WITHOUT_NOTIFY.equals(discussionLevel)) {
final Note firstNote = discussion.getFirstNote();
final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest();
final DiscussionNewPersonalNotify.DiscussionNewPersonalNotifyBuilder messageBuilder = DiscussionNewPersonalNotify.builder()
.url(firstNote.getWebUrl())
.threadId(discussion.getId())
.mergeRequestName(mergeRequest.getTitle())
.authorName(firstNote.getAuthor().getName());
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
final List<Note> notes = discussion.getNotes();
messageBuilder
.discussionMessage(firstNote.getBody());
if (notes.size() > 1) {
for (int i = 1; i < notes.size(); i++) {
final Note note = notes.get(i);
messageBuilder.note(
new Pair<>(note.getAuthor().getName(), note.getBody())
);
}
}
}
notifyService.send(messageBuilder.build());
}
}
private boolean isNeedNotifyNewNote(Discussion discussion) {
final Note firstNote = discussion.getFirstNote();
final Long gitlabUserId = personInformation.getId();
return firstNote.isResolvable() // Тип комментария требует решения (Задачи)
&& gitlabUserId.equals(discussion.getResponsible().getId()) // Ответственный за дискуссию пользователь
&& !gitlabUserId.equals(firstNote.getAuthor().getId()) // Создатель комментария не пользователь системы
&& FALSE.equals(firstNote.getResolved()); // Комментарий не отмечен как решенный
}
/**
* Уведомляет пользователя, если его никнейм упоминается в комментарии.
*/
private void notifyAboutPersonalAnswer(Discussion discussion, Note note) {
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
if (!WITHOUT_NOTIFY.equals(discussionLevel)) {
final Matcher matcher = PATTERN.matcher(note.getBody());
final Set<String> recipientsLogins = new HashSet<>();
while (matcher.find()) {
final String login = matcher.group(0).replace("@", "");
recipientsLogins.add(login);
}
if (recipientsLogins.contains(personInformation.getUsername())) {
final NewCommentPersonalNotify.NewCommentPersonalNotifyBuilder notifyBuilder = NewCommentPersonalNotify.builder()
.threadId(discussion.getId())
.mergeRequestName(discussion.getMergeRequest().getTitle())
.url(note.getWebUrl());
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
final Note firstNote = discussion.getFirstNote();
if (!firstNote.equals(note)) {
notifyBuilder.message(note.getBody())
.authorName(note.getAuthor().getName());
}
if (prevLastNote.isPresent()) {
final Note prevNote = prevLastNote.get();
notifyBuilder.previousMessage(prevNote.getBody());
notifyBuilder.previousAuthor(prevNote.getAuthor().getName());
}
notifyBuilder
.discussionMessage(firstNote.getBody())
.discussionAuthor(firstNote.getAuthor().getName());
}
notifyService.send(notifyBuilder.build());
}
}
}
private void notifyAboutNewAnswer(Discussion discussion, Note note) {
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
if (!WITHOUT_NOTIFY.equals(discussionLevel)
&& !personInformation.getId().equals(note.getAuthor().getId())) {
final Note firstNote = discussion.getFirstNote();
final NewCommentPersonalNotify.NewCommentPersonalNotifyBuilder notifyBuilder = NewCommentPersonalNotify.builder()
.threadId(discussion.getId())
.url(note.getWebUrl())
.mergeRequestName(discussion.getMergeRequest().getTitle());
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
if (prevLastNote.isPresent()) {
final Note prevNote = prevLastNote.get();
notifyBuilder.previousMessage(prevNote.getBody());
notifyBuilder.previousAuthor(prevNote.getAuthor().getName());
}
notifyBuilder
.discussionMessage(firstNote.getBody())
.discussionAuthor(firstNote.getAuthor().getName())
.message(note.getBody())
.authorName(note.getAuthor().getName());
}
notifyService.send(notifyBuilder.build());
}
}
private void notifyAboutCloseThread(Note newNote, Note oldNote, Optional<Note> lastNote) {
final DiscussionLevel level = settingService.getLevelDiscussionNotify();
if (!WITHOUT_NOTIFY.equals(level)) {
if (isResolved(newNote, oldNote)) {
final MergeRequestForDiscussion mergeRequest = oldNote.getDiscussion().getMergeRequest();
final List<Discussion> discussions = discussionService.getAllByMergeRequestId(mergeRequest.getId())
.stream()
.filter(discussion -> Objects.nonNull(discussion.getResponsible()))
.toList();
final long allYouTasks = discussions.stream()
.filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()))
.count();
final long resolvedYouTask = discussions.stream()
.filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()) && discussion.getResolved())
.count();
final ThreadClosePersonalNotify.ThreadClosePersonalNotifyBuilder notifyBuilder = ThreadClosePersonalNotify.builder()
.mergeRequestName(mergeRequest.getTitle())
.url(oldNote.getWebUrl())
.personTasks(allYouTasks)
.personResolvedTasks(resolvedYouTask);
if (NOTIFY_WITH_CONTEXT.equals(level)) {
notifyBuilder
.authorName(oldNote.getAuthor().getName())
.messageTask(oldNote.getBody());
lastNote.ifPresent(
note -> {
notifyBuilder.authorLastNote(note.getAuthor().getName());
notifyBuilder.messageLastNote(note.getBody());
}
);
}
notifyService.send(notifyBuilder.build());
}
}
}
private boolean isResolved(Note note, Note oldNote) {
return checkNull(oldNote.getResolvedBy()) // В старом комментарии не было отметки о решении
&& checkNotNull(note.getResolvedBy()) // А в новом есть отметка
&& personInformation.getId().equals(oldNote.getAuthor().getId()) // и решающий не является пользователем бота
&& !note.getResolvedBy().getId().equals(oldNote.getAuthor().getId()); // и решающий не является автором треда
}
}

View File

@ -1,388 +0,0 @@
package dev.struchkov.bot.gitlab.core.handler;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
import dev.struchkov.bot.gitlab.context.domain.changed.ApprovalChanged;
import dev.struchkov.bot.gitlab.context.domain.changed.AssigneeChanged;
import dev.struchkov.bot.gitlab.context.domain.changed.ReviewerChanged;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import dev.struchkov.bot.gitlab.context.domain.event.NewMergeRequestEvent;
import dev.struchkov.bot.gitlab.context.domain.event.UpdateMergeRequestEvent;
import dev.struchkov.bot.gitlab.context.domain.notify.group.mr.ConflictMrGroupNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.group.mr.NewMergeRequestGroupNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.group.mr.NoReviewerGroupNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ApprovalChangedMrPersonalNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictMrPersonalNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictResolveMrPersonalNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForAssignee;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForReview;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.StatusMrPersonalNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.UpdateMrPersonalNotify;
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
import dev.struchkov.bot.gitlab.context.service.NotifyService;
import dev.struchkov.bot.gitlab.context.service.PersonService;
import dev.struchkov.bot.gitlab.context.service.ProjectService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static java.lang.Boolean.TRUE;
@Component
@RequiredArgsConstructor
public class MergeRequestHandler {
private final NotifyService notifyService;
private final PersonService personService;
private final PersonInformation personInformation;
private final ProjectService projectService;
private final DiscussionService discussionService;
@EventListener
public void newMrHandle(NewMergeRequestEvent event) {
final MergeRequest mergeRequest = event.getMergeRequest();
final String projectName = projectService.getByIdOrThrow(mergeRequest.getProjectId()).getName();
final boolean userReviewer = mergeRequest.isUserReviewer();
final boolean userAssignee = mergeRequest.isUserAssignee();
if (mergeRequest.isConflict()) {
sendGroupNotifyAboutConflict(mergeRequest, projectName);
} else {
if (mergeRequest.isNotification()) {
if (userReviewer || userAssignee) {
if (userReviewer) sendNotifyNewMrReview(mergeRequest, projectName);
if (userAssignee) sendNotifyNewAssignee(mergeRequest, projectName, null);
}
}
sendGroupNotifyForReviewers(mergeRequest, projectName);
}
}
@EventListener
public void updateMrHandle(UpdateMergeRequestEvent event) {
final MergeRequest oldMergeRequest = event.getOldMergeRequest();
final MergeRequest newMergeRequest = event.getNewMergeRequest();
final AssigneeChanged assigneeChanged = event.getAssigneeChanged();
final ReviewerChanged reviewerChanged = event.getReviewerChanged();
final Optional<ApprovalChanged> optApprovalChanged = event.getOptApprovalChanged();
final boolean resolveConflict = oldMergeRequest.isConflict() && !newMergeRequest.isConflict();
final boolean newConflict = !oldMergeRequest.isConflict() && newMergeRequest.isConflict();
final boolean isChangedMr = !oldMergeRequest.getUpdatedDate().equals(newMergeRequest.getUpdatedDate());
final Project project = projectService.getByIdOrThrow(newMergeRequest.getProjectId());
if (oldMergeRequest.isNotification()) {
if (newConflict) {
personalNotifyAboutNewConflict(oldMergeRequest, newMergeRequest, project);
}
if (resolveConflict) {
personalNotifyAboutResolveConflict(oldMergeRequest, newMergeRequest, project);
}
if (isChangedMr) {
personalNotifyAboutStatus(oldMergeRequest, newMergeRequest, project);
personalNotifyAboutUpdate(oldMergeRequest, newMergeRequest, project);
}
if (reviewerChanged.isChanged()) {
notifyReviewer(reviewerChanged, newMergeRequest, project);
}
if (assigneeChanged.isChanged()) {
notifyAssignee(assigneeChanged, oldMergeRequest, newMergeRequest, project);
}
if (optApprovalChanged.isPresent()) {
final ApprovalChanged approvalChanged = optApprovalChanged.get();
notifyApproval(newMergeRequest, project, approvalChanged);
}
}
//групповые уведомления
if (newConflict) {
sendGroupNotifyAboutConflict(newMergeRequest, project.getName());
}
if (reviewerChanged.isChanged()) {
sendGroupNotifyForReviewers(newMergeRequest, project.getName());
}
}
private void sendGroupNotifyAboutConflict(MergeRequest mergeRequest, String projectName) {
final Optional<String> optAuthorUserName = personService.getTelegramUsernamesByPersonIds(mergeRequest.getAuthor().getId());
if (optAuthorUserName.isPresent()) {
final String authorUserName = optAuthorUserName.get();
notifyService.send(
ConflictMrGroupNotify.builder()
.projectName(projectName)
.url(mergeRequest.getWebUrl())
.title(mergeRequest.getTitle())
.milestone(mergeRequest.getMilestone())
.sourceBranch(mergeRequest.getSourceBranch())
.authorTelegramUsername(authorUserName)
.build()
);
}
}
private void sendGroupNotifyAboutNoReviewers(MergeRequest mergeRequest, String projectName) {
final Optional<String> optAuthorUserName = personService.getTelegramUsernamesByPersonIds(mergeRequest.getAuthor().getId());
if (optAuthorUserName.isPresent()) {
final String authorUsername = optAuthorUserName.get();
notifyService.send(
NoReviewerGroupNotify.builder()
.ownerTelegramUsername(authorUsername)
.title(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.milestone(mergeRequest.getMilestone())
.projectName(projectName)
.targetBranch(mergeRequest.getTargetBranch())
.sourceBranch(mergeRequest.getSourceBranch())
.build()
);
}
}
private void sendGroupNotifyForReviewers(MergeRequest mergeRequest, String projectName) {
if (checkNotEmpty(mergeRequest.getReviewers())) {
final Map<Long, String> reviewerTelegramUsernames = personService.getTelegramUsernamesByPersonIds(mergeRequest.getReviewers().stream().map(Person::getId).collect(Collectors.toSet()));
if (!reviewerTelegramUsernames.isEmpty()) {
notifyService.send(
NewMergeRequestGroupNotify.builder()
.mrId(mergeRequest.getId())
.title(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.author(mergeRequest.getAuthor().getName())
.reviewerTelegramUsernames(reviewerTelegramUsernames)
.milestone(mergeRequest.getMilestone())
.projectName(projectName)
.targetBranch(mergeRequest.getTargetBranch())
.sourceBranch(mergeRequest.getSourceBranch())
.description(mergeRequest.getDescription())
.build()
);
}
} else {
sendGroupNotifyAboutNoReviewers(mergeRequest, projectName);
}
}
private void notifyApproval(MergeRequest mergeRequest, Project project, ApprovalChanged approvalChanged) {
final Set<Person> newApproval = approvalChanged.getNewApproval().stream()
.filter(approval -> !personInformation.getId().equals(approval.getId()))
.collect(Collectors.toSet());
final Set<Person> dontApproval = approvalChanged.getDontApprove().stream()
.filter(approval -> !personInformation.getId().equals(approval.getId()))
.collect(Collectors.toSet());
if (checkNotEmpty(newApproval) || checkNotEmpty(dontApproval)) {
notifyService.send(
ApprovalChangedMrPersonalNotify.builder()
.mrId(mergeRequest.getId())
.milestone(mergeRequest.getMilestone())
.projectName(project.getName())
.title(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.newApproval(newApproval)
.dontApproval(dontApproval)
.build()
);
}
}
private void sendNotifyNewMrReview(MergeRequest mergeRequest, String projectName) {
final NewMrForReview.NewMrForReviewBuilder builder = NewMrForReview.builder()
.mrId(mergeRequest.getId())
.projectName(projectName)
.labels(mergeRequest.getLabels())
.author(mergeRequest.getAuthor().getName())
.milestone(mergeRequest.getMilestone())
.description(mergeRequest.getDescription())
.title(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.targetBranch(mergeRequest.getTargetBranch())
.sourceBranch(mergeRequest.getSourceBranch());
getAssignee(mergeRequest)
.map(Person::getName)
.ifPresent(builder::assignee);
notifyService.send(builder.build());
}
private void sendNotifyNewAssignee(MergeRequest mergeRequest, String projectName, String oldAssigneeName) {
final NewMrForAssignee.NewMrForAssigneeBuilder builder = NewMrForAssignee.builder()
.mrId(mergeRequest.getId())
.projectName(projectName)
.labels(mergeRequest.getLabels())
.author(mergeRequest.getAuthor().getName())
.description(mergeRequest.getDescription())
.milestone(mergeRequest.getMilestone())
.title(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.targetBranch(mergeRequest.getTargetBranch())
.sourceBranch(mergeRequest.getSourceBranch())
.milestone(mergeRequest.getMilestone())
.reviewers(mergeRequest.getReviewers().stream().map(Person::getName).toList());
if (checkNotNull(oldAssigneeName)) {
builder.oldAssigneeName(oldAssigneeName);
getAssignee(mergeRequest)
.map(Person::getName)
.ifPresent(builder::newAssigneeName);
}
notifyService.send(builder.build());
}
private void personalNotifyAboutUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
final Long botUserGitlabId = personInformation.getId();
if (
!botUserGitlabId.equals(mergeRequest.getAuthor().getId()) // Автор MR не пользователь приложения
&& !Objects.equals(oldMergeRequest.getDateLastCommit(), mergeRequest.getDateLastCommit())
&& !mergeRequest.isConflict() // MR не находится в состоянии конфликта
&& !botUserGitlabId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан НЕ пользователем бота
) {
long allTask = 0;
long resolvedTask = 0;
long allYouTasks = 0;
long resolvedYouTask = 0;
final List<Discussion> discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId());
for (Discussion discussion : discussions) {
if (checkNotNull(discussion.getResponsible())) {
final boolean isBotUserAuthorDiscussion = botUserGitlabId.equals(discussion.getFirstNote().getAuthor().getId());
allTask += 1;
if (isBotUserAuthorDiscussion) {
allYouTasks += 1;
}
if (TRUE.equals(discussion.getResolved())) {
resolvedTask += 1;
if (isBotUserAuthorDiscussion) {
resolvedYouTask += 1;
}
}
}
}
final UpdateMrPersonalNotify.UpdateMrPersonalNotifyBuilder notifyBuilder = UpdateMrPersonalNotify.builder()
.mrId(oldMergeRequest.getId())
.author(oldMergeRequest.getAuthor().getName())
.name(oldMergeRequest.getTitle())
.projectName(project.getName())
.url(oldMergeRequest.getWebUrl())
.allTasks(allTask)
.milestone(mergeRequest.getMilestone())
.allResolvedTasks(resolvedTask)
.personTasks(allYouTasks)
.personResolvedTasks(resolvedYouTask);
if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) {
notifyBuilder.comment("The conflict has been resolved");
}
notifyService.send(notifyBuilder.build());
}
}
protected void personalNotifyAboutNewConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
final Long gitlabUserId = personInformation.getId();
if (
!oldMergeRequest.isConflict() // У старого MR не было конфликта
&& mergeRequest.isConflict() // А у нового есть
&& gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан пользователем бота
) {
notifyService.send(
ConflictMrPersonalNotify.builder()
.mrId(oldMergeRequest.getId())
.sourceBranch(oldMergeRequest.getSourceBranch())
.name(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.projectKey(project.getName())
.milestone(mergeRequest.getMilestone())
.build()
);
}
}
private void personalNotifyAboutResolveConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
final Long gitlabUserId = personInformation.getId();
if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) {
// проверяем даты коммитов, так как при пуше в target ветку MR у которого есть конфликт, конфликт на время пропадает. Судя по всему GitLab после пуша заново проверяет вероятность конфликта. Чаще всего конфликт никуда не девается.
if (Objects.equals(oldMergeRequest.getDateLastCommit(), mergeRequest.getDateLastCommit())) {
mergeRequest.setConflict(true);
} else {
if (gitlabUserId.equals(oldMergeRequest.getAuthor().getId())) {
notifyService.send(
ConflictResolveMrPersonalNotify.builder()
.mrId(oldMergeRequest.getId())
.sourceBranch(oldMergeRequest.getSourceBranch())
.name(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.projectKey(project.getName())
.milestone(mergeRequest.getMilestone())
.build()
);
}
}
}
}
protected void personalNotifyAboutStatus(MergeRequest oldMergeRequest, MergeRequest newMergeRequest, Project project) {
final MergeRequestState oldStatus = oldMergeRequest.getState();
final MergeRequestState newStatus = newMergeRequest.getState();
final Long gitlabUserId = personInformation.getId();
if (
!oldStatus.equals(newStatus) // статус изменился
&& gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // создатель MR является пользователем бота
) {
notifyService.send(
StatusMrPersonalNotify.builder()
.mrId(oldMergeRequest.getId())
.name(newMergeRequest.getTitle())
.url(oldMergeRequest.getWebUrl())
.projectName(project.getName())
.newStatus(newStatus)
.oldStatus(oldStatus)
.milestone(newMergeRequest.getMilestone())
.build()
);
}
}
private Optional<Person> getAssignee(MergeRequest mergeRequest) {
return Optional.ofNullable(mergeRequest.getAssignee());
}
//TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление
private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
switch (assigneeChanged) {
case BECOME -> sendNotifyNewAssignee(
mergeRequest, project.getName(), getAssignee(oldMergeRequest).map(Person::getName).orElse(null)
);
}
}
//TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление ревьювера
private void notifyReviewer(ReviewerChanged reviewerChanged, MergeRequest mergeRequest, Project project) {
switch (reviewerChanged) {
case BECOME -> sendNotifyNewMrReview(mergeRequest, project.getName());
}
}
}

View File

@ -1,138 +0,0 @@
package dev.struchkov.bot.gitlab.core.handler;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import dev.struchkov.bot.gitlab.context.domain.event.NewPipelineEvent;
import dev.struchkov.bot.gitlab.context.domain.event.UpdatePipelineEvent;
import dev.struchkov.bot.gitlab.context.domain.notify.group.pipeline.PipelineGroupNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.pipeline.PipelinePersonalNotify;
import dev.struchkov.bot.gitlab.context.service.NotifyService;
import dev.struchkov.bot.gitlab.context.service.PersonService;
import dev.struchkov.bot.gitlab.context.service.ProjectService;
import dev.struchkov.haiti.utils.Strings;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CANCELED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.FAILED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SKIPPED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SUCCESS;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
@Component
@RequiredArgsConstructor
public class PipelineHandler {
// Статусы пайплайнов, о которых нужно уведомить
private static final Set<PipelineStatus> notificationStatus = Set.of(FAILED, SUCCESS, CANCELED, SKIPPED);
private final PersonService personService;
private final PersonInformation personInformation;
private final NotifyService notifyService;
private final ProjectService projectService;
@EventListener
public void newPipelineHandle(NewPipelineEvent event) {
final Pipeline pipeline = event.getPipeline();
final Optional<String> optProjectName = projectService.getProjectNameById(pipeline.getProjectId())
.map(Strings::escapeMarkdown);
if (isNeedPersonalNotifyPipeline(pipeline)) {
final PipelinePersonalNotify.PipelinePersonalNotifyBuilder builder = PipelinePersonalNotify.builder()
.newStatus(pipeline.getStatus())
.refName(pipeline.getRef())
.webUrl(pipeline.getWebUrl())
.oldStatus(PipelineStatus.NEW);
optProjectName.ifPresent(builder::projectName);
notifyService.send(builder.build());
}
if (isNeedPersonalGroupPipeline(pipeline)) {
final Optional<String> optTelegramUsername = personService.getTelegramUsernamesByPersonIds(pipeline.getPerson().getId());
if (optTelegramUsername.isPresent()) {
final String telegramUsername = optTelegramUsername.get();
final PipelineGroupNotify.PipelineGroupNotifyBuilder builder = PipelineGroupNotify.builder()
.newStatus(pipeline.getStatus())
.refName(pipeline.getRef())
.webUrl(pipeline.getWebUrl())
.oldStatus(PipelineStatus.NEW)
.ownerTelegramUsername(telegramUsername);
optProjectName.ifPresent(builder::projectName);
notifyService.send(builder.build());
}
}
}
@EventListener
public void updatePipelineHandle(UpdatePipelineEvent event) {
final Pipeline oldPipeline = event.getOldPipeline();
final Pipeline newPipeline = event.getNewPipeline();
if (!Objects.equals(oldPipeline.getUpdated(), newPipeline.getUpdated())) {
final Optional<String> optProjectName = projectService.getProjectNameById(newPipeline.getProjectId())
.map(Strings::escapeMarkdown);
if (isNeedPersonalNotifyPipeline(newPipeline)) {
final PipelinePersonalNotify.PipelinePersonalNotifyBuilder builder = PipelinePersonalNotify.builder()
.newStatus(newPipeline.getStatus())
.refName(newPipeline.getRef())
.webUrl(newPipeline.getWebUrl())
.oldStatus(oldPipeline.getStatus());
optProjectName.ifPresent(builder::projectName);
notifyService.send(builder.build());
}
if (isNeedPersonalGroupPipeline(newPipeline)) {
final Optional<String> optTelegramUsername = personService.getTelegramUsernamesByPersonIds(newPipeline.getPerson().getId());
if (optTelegramUsername.isEmpty()) {
final String telegramUsername = optTelegramUsername.get();
final PipelineGroupNotify.PipelineGroupNotifyBuilder builder = PipelineGroupNotify.builder()
.newStatus(newPipeline.getStatus())
.refName(newPipeline.getRef())
.webUrl(newPipeline.getWebUrl())
.oldStatus(oldPipeline.getStatus())
.ownerTelegramUsername(telegramUsername);
optProjectName.ifPresent(builder::projectName);
notifyService.send(builder.build());
}
}
}
}
private boolean isNeedPersonalNotifyPipeline(@NonNull Pipeline pipeline) {
final Person personPipelineCreator = pipeline.getPerson();
return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления
&& checkNotNull(personPipelineCreator) // Создатель пайплайна не null
&& personInformation.getId().equals(personPipelineCreator.getId()) // Пользователь приложения является инициатором пайплайна
&& LocalDateTime.now().minusDays(1).isBefore(pipeline.getCreated()); // Пайплан был создан не более 24 часов назад
}
private boolean isNeedPersonalGroupPipeline(@NonNull Pipeline pipeline) {
final Person personPipelineCreator = pipeline.getPerson();
return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления
&& checkNotNull(personPipelineCreator) // Создатель пайплайна не null
&& LocalDateTime.now().minusDays(1).isBefore(pipeline.getCreated()); // Пайплан был создан не более 24 часов назад
}
}

View File

@ -1,36 +0,0 @@
package dev.struchkov.bot.gitlab.core.handler;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import dev.struchkov.bot.gitlab.context.domain.event.NewProjectEvent;
import dev.struchkov.bot.gitlab.context.domain.notify.project.NewProjectPersonalNotify;
import dev.struchkov.bot.gitlab.context.service.NotifyService;
import dev.struchkov.bot.gitlab.context.service.PersonService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class ProjectHandler {
private final NotifyService notifyService;
private final PersonService personService;
@EventListener
public void handleNewProjectEvent(NewProjectEvent event) {
final Project newProject = event.getProject();
final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName();
notifyService.send(
NewProjectPersonalNotify.builder()
.projectId(newProject.getId())
.projectDescription(newProject.getDescription())
.projectName(newProject.getName())
.projectUrl(newProject.getWebUrl())
.sshUrlToRepo(newProject.getSshUrlToRepo())
.httpUrlToRepo(newProject.getHttpUrlToRepo())
.authorName(authorName)
.build()
);
}
}

View File

@ -1,185 +0,0 @@
package dev.struchkov.bot.gitlab.core.parser;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
import dev.struchkov.sdk.gitlab.core.GitlabSdkManager;
import dev.struchkov.sdk.gitlab.domain.GitlabUrl;
import dev.struchkov.sdk.gitlab.schema.note.DiscussionJson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static dev.struchkov.haiti.utils.Checker.checkFalse;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Парсер обсуждений.
*
* @author upagge 11.02.2021
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class DiscussionParser {
public static final int PAGE_COUNT = 100;
//TODO [23.08.2024|uPagge]: Убрать
private final GitlabUrl gitlabUrl;
private final GitlabSdkManager gitlabSdkManager;
private final DiscussionService discussionService;
private final MergeRequestsService mergeRequestsService;
private final ConversionService conversionService;
/**
* Поиск новых обсуждений
*/
public void scanNewDiscussion() {
log.debug("Старт обработки новых дискуссий");
final List<MergeRequestForDiscussion> mergeRequests = mergeRequestsService.getAllForDiscussion();
mergeRequests.forEach(this::processingNewDiscussion);
log.debug("Конец обработки новых дискуссий");
}
private void processingNewDiscussion(MergeRequestForDiscussion mergeRequest) {
int page = 1;
final List<DiscussionJson> discussionJson = gitlabSdkManager.getDiscussionForMergeRequest(mergeRequest.getProjectId(), mergeRequest.getTwoId(), page, PAGE_COUNT);
if (checkNotEmpty(discussionJson)) {
while (discussionJson.size() == PAGE_COUNT) {
discussionJson.addAll(gitlabSdkManager.getDiscussionForMergeRequest(mergeRequest.getProjectId(), mergeRequest.getTwoId(), ++page, PAGE_COUNT));
}
createNewDiscussion(discussionJson, mergeRequest);
}
}
private void createNewDiscussion(List<DiscussionJson> discussionJson, MergeRequestForDiscussion mergeRequest) {
final Set<String> discussionIds = discussionJson.stream()
.map(DiscussionJson::getId)
.collect(Collectors.toUnmodifiableSet());
final ExistContainer<Discussion, String> existContainer = discussionService.existsById(discussionIds);
final Set<String> notFoundIds = existContainer.getIdNoFound();
if (checkFalse(existContainer.isAllFound())) {
final List<Discussion> newDiscussions = discussionJson.stream()
.filter(json -> notFoundIds.contains(json.getId()))
.map(json -> {
final Discussion discussion = conversionService.convert(json, Discussion.class);
discussion.setMergeRequest(mergeRequest);
discussion.setResponsible(mergeRequest.getAuthor());
discussion.getNotes().forEach(createNoteLink(mergeRequest));
return discussion;
})
// Фильтрация специально стоит после map(). Таким образом отбрасываются системные уведомления
.filter(discussion -> checkNotEmpty(discussion.getNotes()))
.toList();
if (checkNotEmpty(newDiscussions)) {
personMapping(newDiscussions);
discussionService.createAll(newDiscussions);
}
}
}
private void personMapping(List<Discussion> newDiscussions) {
final Stream<Person> firstStream = Stream.concat(
newDiscussions.stream()
.flatMap(discussion -> discussion.getNotes().stream())
.map(Note::getResolvedBy)
.filter(Objects::nonNull),
newDiscussions.stream()
.flatMap(discussion -> discussion.getNotes().stream())
.map(Note::getAuthor)
.filter(Objects::nonNull)
);
final Map<Long, Person> personMap = Stream.concat(
firstStream,
newDiscussions.stream()
.map(Discussion::getResponsible)
.filter(Objects::nonNull)
).distinct()
.collect(Collectors.toMap(Person::getId, p -> p));
for (Discussion newDiscussion : newDiscussions) {
final Person responsible = newDiscussion.getResponsible();
if (checkNotNull(responsible)) {
newDiscussion.setResponsible(personMap.get(responsible.getId()));
}
for (Note note : newDiscussion.getNotes()) {
note.setAuthor(personMap.get(note.getAuthor().getId()));
final Person resolvedBy = note.getResolvedBy();
if (checkNotNull(resolvedBy)) {
note.setResolvedBy(personMap.get(resolvedBy.getId()));
}
}
}
}
/**
* Сканирование старых обсуждений на предмет новых комментарие
*/
public void scanOldDiscussions() {
log.debug("Старт обработки старых дискуссий");
final List<Discussion> discussions = discussionService.getAll();
final List<Discussion> newDiscussions = new ArrayList<>();
for (Discussion discussion : discussions) {
final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest();
if (checkNotNull(mergeRequest)) {
gitlabSdkManager.getDiscussionById(mergeRequest.getProjectId(), mergeRequest.getTwoId(), discussion.getId())
.map(json -> {
final Discussion newDiscussion = conversionService.convert(json, Discussion.class);
newDiscussion.getNotes().forEach(createNoteLink(mergeRequest));
return newDiscussion;
}).ifPresent(newDiscussions::add);
} else {
discussionService.deleteById(discussion.getId());
}
}
if (checkNotEmpty(newDiscussions)) {
personMapping(newDiscussions);
discussionService.updateAll(newDiscussions);
}
log.debug("Конец обработки старых дискуссий");
}
private Consumer<Note> createNoteLink(MergeRequestForDiscussion mergeRequest) {
return note -> {
final String url = MessageFormat.format(
gitlabUrl.getNote(),
mergeRequest.getWebUrl(),
note.getId()
);
note.setWebUrl(url);
};
}
}

View File

@ -1,154 +0,0 @@
package dev.struchkov.bot.gitlab.core.parser;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
import dev.struchkov.bot.gitlab.context.service.ProjectService;
import dev.struchkov.haiti.utils.container.Pair;
import dev.struchkov.sdk.gitlab.core.GitlabSdkManager;
import dev.struchkov.sdk.gitlab.schema.approval.ApprovalJson;
import dev.struchkov.sdk.gitlab.schema.mergerequest.MergeRequestJson;
import dev.struchkov.sdk.gitlab.schema.repository.CommitJson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static java.util.stream.Collectors.toList;
@Slf4j
@Service
@RequiredArgsConstructor
public class MergeRequestParser {
private static final Set<MergeRequestState> OLD_STATUSES = Set.of(
MergeRequestState.MERGED, MergeRequestState.OPENED, MergeRequestState.CLOSED
);
private final GitlabSdkManager gitlabSdkManager;
private final MergeRequestsService mergeRequestsService;
private final ProjectService projectService;
private final ConversionService conversionService;
public void parsingOldMergeRequest() {
log.debug("Старт обработки старых MR");
final Set<Pair<Long, Long>> existIds = mergeRequestsService.getAllId(OLD_STATUSES).stream()
.map(idAndStatusPr -> new Pair<>(idAndStatusPr.getProjectId(), idAndStatusPr.getTwoId()))
.collect(Collectors.toSet());
final List<MergeRequest> newMergeRequests = gitlabSdkManager.getAllMergeRequestById(existIds).stream()
.map(mergeRequestJson -> {
final MergeRequest newMergeRequest = conversionService.convert(mergeRequestJson, MergeRequest.class);
parsingCommits(newMergeRequest);
parsingApprovals(newMergeRequest);
return newMergeRequest;
})
.collect(toList());
if (checkNotEmpty(newMergeRequests)) {
personMapping(newMergeRequests);
mergeRequestsService.updateAll(newMergeRequests);
}
log.debug("Конец обработки старых MR");
}
public void parsingNewMergeRequest() {
log.debug("Старт обработки новых MR");
final Set<Long> projectIds = projectService.getAllIdByProcessingEnable();
final List<MergeRequestJson> mergeRequestJsons = gitlabSdkManager.getAllMergeRequestByProjectIds(projectIds);
if (checkNotEmpty(mergeRequestJsons)) {
final Set<Long> jsonIds = mergeRequestJsons.stream()
.map(MergeRequestJson::getId)
.collect(Collectors.toSet());
final ExistContainer<MergeRequest, Long> existContainer = mergeRequestsService.existsById(jsonIds);
log.trace("Из {} полученных MR не найдены в хранилище {}", jsonIds.size(), existContainer.getIdNoFound().size());
if (!existContainer.isAllFound()) {
final List<MergeRequest> newMergeRequests = mergeRequestJsons.stream()
.filter(json -> existContainer.getIdNoFound().contains(json.getId()))
.map(json -> {
final MergeRequest mergeRequest = conversionService.convert(json, MergeRequest.class);
parsingCommits(mergeRequest);
parsingApprovals(mergeRequest);
return mergeRequest;
})
.toList();
personMapping(newMergeRequests);
log.trace("Пачка новых MR обработана и отправлена на сохранение. Количество: {} шт.", newMergeRequests.size());
mergeRequestsService.createAll(newMergeRequests);
}
}
log.debug("Конец обработки новых MR");
}
private static void personMapping(List<MergeRequest> newMergeRequests) {
final Map<Long, Person> personMap = Stream.concat(
newMergeRequests.stream()
.flatMap(mergeRequest -> Stream.of(mergeRequest.getAssignee(), mergeRequest.getAuthor())),
newMergeRequests.stream()
.flatMap(mergeRequest -> Stream.concat(mergeRequest.getReviewers().stream(), mergeRequest.getApprovals().stream()))
).distinct()
.filter(Objects::nonNull)
.collect(Collectors.toMap(Person::getId, p -> p));
for (MergeRequest newMergeRequest : newMergeRequests) {
newMergeRequest.setAuthor(personMap.get(newMergeRequest.getAuthor().getId()));
final Person assignee = newMergeRequest.getAssignee();
if (checkNotNull(assignee)) {
newMergeRequest.setAssignee(personMap.get(assignee.getId()));
}
newMergeRequest.setReviewers(
newMergeRequest.getReviewers().stream()
.map(reviewer -> personMap.get(reviewer.getId()))
.collect(toList())
);
newMergeRequest.setApprovals(
newMergeRequest.getApprovals().stream()
.map(approval -> personMap.get(approval.getId()))
.collect(toList())
);
}
}
//TODO [19.01.2024|uPagge]: Переделать в многопоточный режим
private void parsingCommits(MergeRequest mergeRequest) {
final List<CommitJson> commitJson = gitlabSdkManager.getAllCommitByProjectId(mergeRequest.getProjectId(), mergeRequest.getTwoId());
if (checkNotEmpty(commitJson)) {
mergeRequest.setDateLastCommit(commitJson.get(0).getCreatedDate());
}
}
//TODO [19.01.2024|uPagge]: Переделать в многопоточный режим
private void parsingApprovals(MergeRequest mergeRequest) {
final List<Person> personApprovals = gitlabSdkManager.getAllApprovalForMergeRequest(mergeRequest.getProjectId(), mergeRequest.getTwoId()).stream()
.map(ApprovalJson::getUser)
.map(personJson -> conversionService.convert(personJson, Person.class))
.collect(toList());
if (checkNotEmpty(personApprovals)) {
mergeRequest.setApprovals(personApprovals);
}
}
}

View File

@ -1,111 +0,0 @@
package dev.struchkov.bot.gitlab.core.parser;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import dev.struchkov.bot.gitlab.context.service.PipelineService;
import dev.struchkov.bot.gitlab.context.service.ProjectService;
import dev.struchkov.haiti.utils.container.Pair;
import dev.struchkov.sdk.gitlab.core.GitlabSdkManager;
import dev.struchkov.sdk.gitlab.schema.pipeline.PipelineShortJson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CREATED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.MANUAL;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.PENDING;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.PREPARING;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.RUNNING;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.WAITING_FOR_RESOURCE;
import static dev.struchkov.haiti.utils.Checker.checkFalse;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
/**
* Парсер пайплайнов.
*
* @author upagge 17.01.2021
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class PipelineParser {
private static final Set<PipelineStatus> oldSOLD_STATUSES = Set.of(
CREATED, WAITING_FOR_RESOURCE, PREPARING, PENDING, RUNNING, MANUAL
);
private final GitlabSdkManager gitlabSdkManager;
private final PipelineService pipelineService;
private final ProjectService projectService;
private final ConversionService conversionService;
private LocalDateTime lastUpdate = LocalDateTime.now();
public void scanNewPipeline() {
log.debug("Старт обработки новых пайплайнов");
final Set<Long> projectIds = projectService.getAllIdByProcessingEnable();
final Map<Long, Long> pipelineProjectMap = getPipelineShortJsons(projectIds).stream()
.collect(toMap(PipelineShortJson::getId, PipelineShortJson::getProjectId));
if (checkNotEmpty(pipelineProjectMap)) {
final ExistContainer<Pipeline, Long> existContainer = pipelineService.existsById(pipelineProjectMap.keySet());
if (checkFalse(existContainer.isAllFound())) {
final Set<Pair<Long, Long>> idsNotFound = existContainer.getIdNoFound().stream()
.map(pipelineId -> new Pair<>(pipelineProjectMap.get(pipelineId), pipelineId))
.collect(toSet());
final List<Pipeline> newPipelines = gitlabSdkManager.getAllPipelineForProject(idsNotFound).stream()
.map(json -> conversionService.convert(json, Pipeline.class))
.collect(Collectors.toList());
;
if (checkNotEmpty(newPipelines)) {
pipelineService.createAll(newPipelines);
}
}
}
log.debug("Конец обработки новых пайплайнов");
}
private List<PipelineShortJson> getPipelineShortJsons(Set<Long> projectIds) {
final LocalDateTime newLastUpdate = LocalDateTime.now();
final List<PipelineShortJson> pipelineJsons = gitlabSdkManager.getAllPipeline(projectIds, lastUpdate.minusHours(12L));
lastUpdate = newLastUpdate;
return pipelineJsons;
}
public void scanOldPipeline() {
log.debug("Старт обработки старых пайплайнов");
final List<Pipeline> pipelines = pipelineService.getAllByStatuses(oldSOLD_STATUSES);
final List<Pipeline> newPipelines = gitlabSdkManager.getAllPipelineForProject(
pipelines.stream()
.map(pipeline -> new Pair<>(pipeline.getProjectId(), pipeline.getId()))
.collect(toSet())
).stream()
.map(json -> conversionService.convert(json, Pipeline.class))
.collect(Collectors.toList());
if (checkNotEmpty(newPipelines)) {
pipelineService.updateAll(newPipelines);
}
log.debug("Конец обработки старых пайплайнов");
}
}

View File

@ -1,113 +0,0 @@
package dev.struchkov.bot.gitlab.core.parser;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import dev.struchkov.bot.gitlab.context.service.PersonService;
import dev.struchkov.bot.gitlab.context.service.ProjectService;
import dev.struchkov.sdk.gitlab.core.GitlabSdkManager;
import dev.struchkov.sdk.gitlab.domain.GitlabProjectParam;
import dev.struchkov.sdk.gitlab.schema.repository.ProjectJson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.context.exception.ConvertException.convertException;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
/**
* Парсер проектов.
*
* @author upagge 14.01.2021
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class ProjectParser {
private final GitlabSdkManager gitlabSdkManager;
private final ConversionService conversionService;
private final ProjectService projectService;
private final PersonService personService;
public void parseAllProjectOwner() {
log.debug("Старт обработки всех проектов, где пользователь владелец");
parseProjects(GitlabProjectParam.OWNER);
log.debug("Конец обработки всех проектов, где пользователь владелец");
}
public void parseAllPrivateProject() {
log.debug("Старт обработки приватных проектов");
parseProjects(GitlabProjectParam.PRIVATE);
log.debug("Конец обработки приватных проектов");
}
private void parseProjects(GitlabProjectParam param) {
int page = 1;
List<ProjectJson> projectJsons = gitlabSdkManager.getAllProject(page, param);
while (checkNotEmpty(projectJsons)) {
final Set<Long> projectIds = projectJsons.stream()
.map(ProjectJson::getId)
.collect(Collectors.toUnmodifiableSet());
createNewPersons(projectJsons);
final ExistContainer<Project, Long> existContainer = projectService.existsById(projectIds);
final List<Project> newProjects = projectJsons.stream()
.filter(json -> existContainer.getIdNoFound().contains(json.getId()))
.map(json -> conversionService.convert(json, Project.class))
.toList();
if (checkNotEmpty(newProjects)) {
projectService.createAll(newProjects);
}
projectJsons = gitlabSdkManager.getAllProject(++page, param);
}
}
public Project parseByUrl(String projectUrl) {
final ProjectJson projectJson = gitlabSdkManager.getProjectByUrl(projectUrl)
.orElseThrow(convertException("Error adding a repository"));
if (!projectService.existsById(projectJson.getId())) {
createNewPersons(List.of(projectJson));
final Project newProject = conversionService.convert(projectJson, Project.class);
return projectService.create(newProject, false);
} else {
return projectService.getByIdOrThrow(projectJson.getId());
}
}
private void createNewPersons(List<ProjectJson> projectJsons) {
final Set<Long> personCreatorId = projectJsons.stream()
.map(ProjectJson::getCreatorId)
.collect(Collectors.toSet());
final ExistContainer<Person, Long> existContainer = personService.existsById(personCreatorId);
if (!existContainer.isAllFound()) {
final Collection<Long> notFoundId = existContainer.getIdNoFound();
final List<Person> newPersons = notFoundId.stream()
.map(
userId -> gitlabSdkManager.getPersonById(userId)
.map(json -> conversionService.convert(json, Person.class))
.orElseThrow(convertException("Ошибка преобразования нового пользователя"))
).toList();
personService.createAll(newPersons);
}
}
}

View File

@ -1,111 +0,0 @@
package dev.struchkov.bot.gitlab.core.service;
import dev.struchkov.bot.gitlab.context.domain.entity.AppSetting;
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
import dev.struchkov.bot.gitlab.context.repository.AppSettingRepository;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.haiti.context.exception.NotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.UUID;
import java.util.function.Supplier;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
/**
* Сервис отвечает за пользовательские настройки приложения.
*
* @author upagge 16.01.2021
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AppSettingServiceImpl implements AppSettingService {
private static final Long KEY = 1L;
public static final Supplier<NotFoundException> NOT_FOUND_SETTINGS = notFoundException("Ошибка, невозможно найти настройки приложения, проверьте базу данных.");
private final AppSettingRepository appSettingRepository;
@Override
@Transactional(readOnly = true)
public boolean isFirstStart() {
return getAppSetting().isFirstStart();
}
@Override
@Transactional
public void disableFirstStart() {
final AppSetting appSetting = getAppSetting();
appSetting.setFirstStart(false);
log.info("Первичная настройка закончена");
}
@Override
@Transactional(readOnly = true)
public boolean isEnableAllNotify() {
return getAppSetting().isEnableNotify();
}
@Override
@Transactional
public void turnOnAllNotify() {
final AppSetting appSetting = getAppSetting();
appSetting.setEnableNotify(true);
log.info("Получение всех уведомлений активировано");
}
@Override
@Transactional
public void privateProjectScan(boolean enable) {
final AppSetting appSetting = getAppSetting();
appSetting.setProjectPrivateScan(enable);
}
@Override
@Transactional
public void ownerProjectScan(boolean enable) {
final AppSetting appSetting = getAppSetting();
appSetting.setProjectOwnerScan(enable);
}
@Override
public boolean isOwnerProjectScan() {
return getAppSetting().isProjectOwnerScan();
}
@Override
public boolean isPrivateProjectScan() {
return getAppSetting().isProjectPrivateScan();
}
@Override
public DiscussionLevel getLevelDiscussionNotify() {
return getAppSetting().getDiscussionNotifyLevel();
}
@Override
@Transactional
public void setDiscussionLevel(DiscussionLevel level) {
final AppSetting appSetting = getAppSetting();
appSetting.setDiscussionNotifyLevel(level);
}
@Override
@Transactional
public UUID getServiceKey() {
final AppSetting appSetting = getAppSetting();
if (appSetting.getServiceKey() == null) {
appSetting.setServiceKey(UUID.randomUUID());
}
return appSetting.getServiceKey();
}
private AppSetting getAppSetting() {
return appSettingRepository.findById(KEY)
.orElseThrow(NOT_FOUND_SETTINGS);
}
}

View File

@ -1,174 +0,0 @@
package dev.struchkov.bot.gitlab.core.service;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
import dev.struchkov.sdk.gitlab.core.GitlabSdkManager;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.bot.gitlab.context.domain.event.NewDiscussionEvent.newDiscussion;
import static dev.struchkov.bot.gitlab.context.domain.event.UpdateDiscussionEvent.updateDiscussion;
import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.WITHOUT_NOTIFY;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Сервис для работы с дискуссиями.
*
* @author upagge 11.02.2021
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DiscussionServiceImpl implements DiscussionService {
private final DiscussionRepository repository;
private final AppSettingService settingService;
private final GitlabSdkManager gitlabSdkManager;
private final ApplicationEventPublisher eventPublisher;
@Override
@Transactional
public Discussion create(@NonNull Discussion discussion) {
final DiscussionLevel levelDiscussionNotify = settingService.getLevelDiscussionNotify();
if (!WITHOUT_NOTIFY.equals(levelDiscussionNotify)) {
discussion.setNotification(true);
eventPublisher.publishEvent(newDiscussion(discussion));
} else {
discussion.setNotification(false);
}
final boolean resolved = discussion.getNotes().stream()
.allMatch(note -> note.isResolvable() && note.getResolved());
discussion.setResolved(resolved);
return repository.save(discussion);
}
@Override
@Transactional
public Discussion update(@NonNull Discussion discussion) {
final Discussion oldDiscussion = repository.findById(discussion.getId())
.orElseThrow(notFoundException("Дискуссия не найдена"));
discussion.setResponsible(oldDiscussion.getResponsible());
discussion.setMergeRequest(oldDiscussion.getMergeRequest());
discussion.setNotification(oldDiscussion.isNotification());
final Person responsiblePerson = discussion.getResponsible();
if (checkNotNull(responsiblePerson)) {
for (Note note : discussion.getNotes()) {
if (responsiblePerson.getId().equals(note.getAuthor().getId())) {
note.setAuthor(responsiblePerson);
}
final Person resolvedBy = note.getResolvedBy();
if (checkNotNull(resolvedBy)) {
if (responsiblePerson.getId().equals(resolvedBy.getId())) {
note.setResolvedBy(responsiblePerson);
}
}
}
}
final boolean resolved = discussion.getNotes().stream()
.allMatch(note -> note.isResolvable() && note.getResolved());
discussion.setResolved(resolved);
eventPublisher.publishEvent(updateDiscussion(oldDiscussion, discussion));
return repository.save(discussion);
}
@Override
public List<Discussion> updateAll(@NonNull List<Discussion> discussions) {
return discussions.stream()
.map(this::update)
.collect(Collectors.toList());
}
@Override
public void answer(@NonNull String discussionId, @NonNull String text) {
final Discussion discussion = repository.findById(discussionId)
.orElseThrow(notFoundException("Дисскусия {0} не найдена", discussionId));
final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest();
final Long projectId = mergeRequest.getProjectId();
gitlabSdkManager.sendMessageToDiscussion(projectId, mergeRequest.getTwoId(), discussionId, text);
}
@Override
public List<Discussion> getAllByMergeRequestId(@NonNull Long mergeRequestId) {
return repository.findAllByMergeRequestId(mergeRequestId);
}
@Override
public ExistContainer<Discussion, String> existsById(@NonNull Set<String> discussionIds) {
final List<Discussion> existsEntity = repository.findAllById(discussionIds);
final Set<String> existsIds = existsEntity.stream().map(Discussion::getId).collect(Collectors.toSet());
if (existsIds.containsAll(discussionIds)) {
return ExistContainer.allFind(existsEntity);
} else {
final Set<String> noExistsId = discussionIds.stream()
.filter(id -> !existsIds.contains(id))
.collect(Collectors.toSet());
return ExistContainer.notAllFind(existsEntity, noExistsId);
}
}
@Override
public List<Discussion> createAll(@NonNull List<Discussion> newDiscussions) {
return newDiscussions.stream()
.map(this::create)
.toList();
}
@Override
public List<Discussion> getAll() {
return repository.findAll();
}
@Override
public Set<String> getAllIds() {
return repository.findAllIds();
}
@Override
@Transactional
public void deleteById(@NonNull String discussionId) {
repository.deleteById(discussionId);
}
@Override
@Transactional
public void cleanOld() {
log.debug("Старт очистки старых дискуссий");
repository.cleanOld();
log.debug("Конец очистки старых дискуссий");
}
@Override
@Transactional
public void notification(boolean enable, String discussionId) {
repository.notification(enable, discussionId);
}
}

View File

@ -1,199 +0,0 @@
package dev.struchkov.bot.gitlab.core.service;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
import dev.struchkov.bot.gitlab.context.domain.changed.ApprovalChanged;
import dev.struchkov.bot.gitlab.context.domain.changed.AssigneeChanged;
import dev.struchkov.bot.gitlab.context.domain.changed.ReviewerChanged;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.repository.MergeRequestRepository;
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.bot.gitlab.context.domain.MergeRequestState.CLOSED;
import static dev.struchkov.bot.gitlab.context.domain.MergeRequestState.MERGED;
import static dev.struchkov.bot.gitlab.context.domain.event.NewMergeRequestEvent.newMergeRequest;
import static dev.struchkov.bot.gitlab.context.domain.event.UpdateMergeRequestEvent.updateMergeRequest;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
@Slf4j
@Service
@RequiredArgsConstructor
public class MergeRequestsServiceImpl implements MergeRequestsService {
public static final Set<MergeRequestState> DELETE_STATES = Set.of(MERGED, CLOSED);
private final ApplicationEventPublisher eventPublisher;
private final MergeRequestRepository repository;
private final PersonInformation personInformation;
@Override
@Transactional
public MergeRequest create(@NonNull MergeRequest mergeRequest) {
final boolean botUserReviewer = isBotUserReviewer(mergeRequest);
final boolean botUserAssignee = isBotUserAssigneeAndNotAuthor(mergeRequest);
final boolean botUserAuthor = personInformation.getId().equals(mergeRequest.getAuthor().getId());
mergeRequest.setNotification(botUserReviewer || botUserAssignee || botUserAuthor);
mergeRequest.setUserAssignee(botUserAssignee);
mergeRequest.setUserReviewer(botUserReviewer);
final MergeRequest savedMergeRequest = repository.save(mergeRequest);
eventPublisher.publishEvent(newMergeRequest(savedMergeRequest));
return savedMergeRequest;
}
private boolean isBotUserAssigneeAndNotAuthor(MergeRequest mergeRequest) {
final Long gitlabUserId = personInformation.getId();
final Optional<Person> optAssignee = getAssignee(mergeRequest);
final Person author = mergeRequest.getAuthor();
if (optAssignee.isPresent()) {
final Person assignee = optAssignee.get();
if (gitlabUserId.equals(assignee.getId()) && !isAuthorSameAssignee(author, assignee)) {
return true;
}
}
return false;
}
/**
* Создатель MR является ответственным за этот MR
*
* @return true, если автор и ответственный один и тот же человек.
*/
private boolean isAuthorSameAssignee(Person author, Person assignee) {
return author.getId().equals(assignee.getId());
}
private boolean isBotUserReviewer(MergeRequest savedMergeRequest) {
final List<Person> reviewers = savedMergeRequest.getReviewers();
final Long botUserGitlabId = personInformation.getId();
if (checkNotEmpty(reviewers)) {
for (Person reviewer : reviewers) {
if (botUserGitlabId.equals(reviewer.getId())) {
return true;
}
}
}
return false;
}
@Override
@Transactional
public MergeRequest update(@NonNull MergeRequest mergeRequest) {
final MergeRequest oldMergeRequest = repository.findById(mergeRequest.getId())
.orElseThrow(notFoundException("MergeRequest не найден"));
mergeRequest.setNotification(oldMergeRequest.isNotification());
final Long gitlabUserId = personInformation.getId();
final AssigneeChanged assigneeChanged = AssigneeChanged.valueOf(gitlabUserId, getAssignee(oldMergeRequest), getAssignee(mergeRequest));
final ReviewerChanged reviewerChanged = ReviewerChanged.valueOf(gitlabUserId, oldMergeRequest.getReviewers(), mergeRequest.getReviewers());
final Optional<ApprovalChanged> optApprovalChanged = ApprovalChanged.approvalChanged(oldMergeRequest.getApprovals(), mergeRequest.getApprovals());
mergeRequest.setUserAssignee(assigneeChanged.getNewStatus(oldMergeRequest.isUserAssignee()));
mergeRequest.setUserReviewer(reviewerChanged.getNewStatus(oldMergeRequest.isUserReviewer()));
eventPublisher.publishEvent(
updateMergeRequest(oldMergeRequest, mergeRequest, assigneeChanged, reviewerChanged, optApprovalChanged)
);
return repository.save(mergeRequest);
}
@Override
@Transactional
public List<MergeRequest> updateAll(@NonNull List<MergeRequest> mergeRequests) {
return mergeRequests.stream()
.map(this::update)
.collect(Collectors.toList());
}
@Override
public Set<IdAndStatusPr> getAllId(Set<MergeRequestState> statuses) {
return repository.findAllIdByStateIn(statuses);
}
@Override
public List<MergeRequestForDiscussion> getAllForDiscussion() {
return repository.findAllForDiscussion();
}
@Override
public ExistContainer<MergeRequest, Long> existsById(@NonNull Set<Long> mergeRequestIds) {
final List<MergeRequest> existsEntity = repository.findAllById(mergeRequestIds);
final Set<Long> existsIds = existsEntity.stream().map(MergeRequest::getId).collect(Collectors.toSet());
if (existsIds.containsAll(mergeRequestIds)) {
return ExistContainer.allFind(existsEntity);
} else {
final Set<Long> noExistsId = mergeRequestIds.stream()
.filter(id -> !existsIds.contains(id))
.collect(Collectors.toSet());
return ExistContainer.notAllFind(existsEntity, noExistsId);
}
}
@Override
public List<MergeRequest> createAll(List<MergeRequest> newMergeRequests) {
return newMergeRequests.stream()
.map(this::create)
.toList();
}
@Override
public List<MergeRequest> getAllByReviewerId(@NonNull Long personId) {
return repository.findAllByReviewerId(personId);
}
@Override
public void cleanOld() {
log.debug("Старт очистки старых MR");
repository.deleteByStates(DELETE_STATES);
log.debug("Конец очистки старых MR");
}
@Override
@Transactional(readOnly = true)
public Set<Long> getAllIds() {
return repository.findAllIds();
}
@Override
@Transactional
public void notification(boolean enable, @NonNull Long mrId) {
repository.notification(enable, mrId);
}
@Override
@Transactional
public void notificationByProjectId(boolean enable, @NonNull Set<Long> projectIds) {
repository.notificationByProjectId(enable, projectIds);
}
private Optional<Person> getAssignee(MergeRequest mergeRequest) {
return Optional.ofNullable(mergeRequest.getAssignee());
}
}

View File

@ -1,40 +0,0 @@
package dev.struchkov.bot.gitlab.core.service;
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
import dev.struchkov.bot.gitlab.context.repository.NoteRepository;
import dev.struchkov.bot.gitlab.context.service.NoteService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
@Slf4j
@Service
@RequiredArgsConstructor
public class NoteServiceImpl implements NoteService {
private final NoteRepository noteRepository;
@Override
public Page<Note> getAllByResolved(boolean resolved, @NonNull Pageable pagination) {
return noteRepository.findAllByResolved(resolved, pagination);
}
@Override
public Note getByIdOrThrow(@NonNull Long noteId) {
return noteRepository.findById(noteId)
.orElseThrow(notFoundException("Note не найдено"));
}
@Override
public List<Note> getAllPersonTask(@NonNull Long userId, boolean resolved) {
return noteRepository.findAllByResponsibleIdAndResolved(userId, resolved);
}
}

Some files were not shown because too many files have changed in this diff Show More