Compare commits
9 Commits
master
...
feature/sm
| Author | SHA1 | Date |
|---|---|---|
|
|
8b9643b60a | |
|
|
d0c7ca03fb | |
|
|
18248a2773 | |
|
|
4a32a1c09d | |
|
|
6865e3fdb8 | |
|
|
0e381ff70c | |
|
|
5770faf7db | |
|
|
6b16393ccb | |
|
|
301c952ef9 |
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.touchin.common.spring.annotations
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
|
import ru.touchin.common.spring.processors.RequiredByBeanDefinitionPostProcessor
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS)
|
||||||
|
@Import(RequiredByBeanDefinitionPostProcessor::class)
|
||||||
|
annotation class RequiredBy(vararg val value: String)
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package ru.touchin.common.spring.processors
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import ru.touchin.common.spring.annotations.RequiredBy
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class RequiredByBeanDefinitionPostProcessor : BeanDefinitionRegistryPostProcessor {
|
||||||
|
|
||||||
|
@Throws(BeansException::class)
|
||||||
|
override fun postProcessBeanDefinitionRegistry(registry: BeanDefinitionRegistry) {
|
||||||
|
for (beanName in registry.beanDefinitionNames) {
|
||||||
|
val beanClassName = registry.getBeanDefinition(beanName).beanClassName?:continue
|
||||||
|
|
||||||
|
getDependantBeanNames(beanClassName).forEach { dependantBeanName ->
|
||||||
|
registry.getBeanDefinition(dependantBeanName).setDependsOn(beanName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(BeansException::class)
|
||||||
|
override fun postProcessBeanFactory(beanFactory: ConfigurableListableBeanFactory) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDependantBeanNames(beanClassName: String): List<String> {
|
||||||
|
val beanClass = Class.forName(beanClassName)
|
||||||
|
var dependantBeans = emptyList<String>()
|
||||||
|
|
||||||
|
if (beanClass.isAnnotationPresent(RequiredBy::class.java)) {
|
||||||
|
dependantBeans = beanClass.getAnnotation(RequiredBy::class.java).value.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependantBeans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
||||||
|
|
@ -58,3 +58,4 @@ include("s3-storage")
|
||||||
include("server-info-spring-web")
|
include("server-info-spring-web")
|
||||||
include("geoip-core")
|
include("geoip-core")
|
||||||
include("user-agent")
|
include("user-agent")
|
||||||
|
include("smart-migration")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
plugins {
|
||||||
|
id("kotlin")
|
||||||
|
id("kotlin-spring")
|
||||||
|
id("maven-publish")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
implementation("org.springframework.boot:spring-boot")
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||||
|
implementation project(":common-spring")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
@file:Suppress("unused")
|
||||||
|
package ru.touchin.smartmigration
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import ru.touchin.common.spring.annotations.RequiredBy
|
||||||
|
import ru.touchin.smartmigration.logic.DataSourceSQL
|
||||||
|
import ru.touchin.smartmigration.logic.factory.DataSourceSqlFactoryImpl
|
||||||
|
import java.sql.Date
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import javax.annotation.PostConstruct
|
||||||
|
import javax.sql.DataSource
|
||||||
|
|
||||||
|
private val SQL_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
|
||||||
|
|
||||||
|
private val CURRENT_TIME_SQL: String
|
||||||
|
get() = SQL_DATE_FORMAT.format(Date(System.currentTimeMillis()))
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredBy("liquibase")
|
||||||
|
class BeforeLiquibase(
|
||||||
|
private val dataSource: DataSource
|
||||||
|
) {
|
||||||
|
|
||||||
|
val dataSourceSql: DataSourceSQL = DataSourceSqlFactoryImpl()
|
||||||
|
.getDataSourceSql(dataSource.connection.metaData.databaseProductName)
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
fun doAction() {
|
||||||
|
val buildNumber = System.getenv("BUILD_NUMBER")
|
||||||
|
?: return
|
||||||
|
|
||||||
|
checkMigrationTable()
|
||||||
|
|
||||||
|
if (checkBuildMigrationExecuted(buildNumber)) {
|
||||||
|
System.setProperty("spring.liquibase.enabled", "false")
|
||||||
|
} else {
|
||||||
|
insertMigration(buildNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkBuildMigrationExecuted(buildNumber: String): Boolean {
|
||||||
|
return dataSourceSql.getMigrationCheckSQL(buildNumber).let {
|
||||||
|
dataSource.connection.createStatement().executeQuery(it).next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkMigrationTable() {
|
||||||
|
dataSourceSql.getTableCheckSQL().let {
|
||||||
|
dataSource.connection.createStatement().execute(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun insertMigration(buildNumber: String) {
|
||||||
|
dataSourceSql.getInsertMigrationSQL(buildNumber, CURRENT_TIME_SQL).let {
|
||||||
|
dataSource.connection.createStatement().execute(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ru.touchin.smartmigration
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan("ru.touchin.smartmigration")
|
||||||
|
open class SmartMigrationConfig
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.touchin.smartmigration.annotation
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
|
import ru.touchin.smartmigration.SmartMigrationConfig
|
||||||
|
|
||||||
|
@Import(SmartMigrationConfig::class)
|
||||||
|
annotation class EnableSmartMigration
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package ru.touchin.smartmigration.logic
|
||||||
|
|
||||||
|
interface DataSourceSQL {
|
||||||
|
|
||||||
|
fun getTableCheckSQL(): String
|
||||||
|
|
||||||
|
fun getMigrationCheckSQL(buildNumber: String): String
|
||||||
|
|
||||||
|
fun getInsertMigrationSQL(buildNumber: String, formattedTime: String): String
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package ru.touchin.smartmigration.logic
|
||||||
|
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
|
||||||
|
private const val MIGRATION_TABLE_NAME = "SMART_MIGRATION"
|
||||||
|
|
||||||
|
class PostgresDataSourceImpl: DataSourceSQL {
|
||||||
|
|
||||||
|
@Language("SQL")
|
||||||
|
override fun getTableCheckSQL(): String {
|
||||||
|
return """
|
||||||
|
CREATE TABLE IF NOT EXISTS smart_migration (
|
||||||
|
ID BIGSERIAL PRIMARY KEY,
|
||||||
|
BUILD_NUMBER VARCHAR(255) NOT NULL,
|
||||||
|
DATE timestamp NOT NULL
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
@Language("SQL")
|
||||||
|
override fun getMigrationCheckSQL(buildNumber: String): String {
|
||||||
|
return "SELECT * FROM $MIGRATION_TABLE_NAME WHERE BUILD_NUMBER = '$buildNumber'"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Language("SQL")
|
||||||
|
override fun getInsertMigrationSQL(buildNumber: String, formattedTime: String): String {
|
||||||
|
return """
|
||||||
|
INSERT INTO $MIGRATION_TABLE_NAME (BUILD_NUMBER, DATE)
|
||||||
|
VALUES ('$buildNumber', '$formattedTime');
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package ru.touchin.smartmigration.logic
|
||||||
|
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
|
||||||
|
private const val MIGRATION_TABLE_NAME = "SMART_MIGRATION"
|
||||||
|
|
||||||
|
class SqlDatasourceImpl:DataSourceSQL {
|
||||||
|
|
||||||
|
@Language("TSQL")
|
||||||
|
override fun getTableCheckSQL(): String {
|
||||||
|
return """
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT * FROM sysobjects WHERE name = '$MIGRATION_TABLE_NAME' and xtype='U'
|
||||||
|
)
|
||||||
|
CREATE TABLE SMART_MIGRATION (
|
||||||
|
ID BIGINT PRIMARY KEY IDENTITY ,
|
||||||
|
BUILD_NUMBER VARCHAR(255) NOT NULL,
|
||||||
|
DATE DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
@Language("TSQL")
|
||||||
|
override fun getMigrationCheckSQL(buildNumber: String): String {
|
||||||
|
return "SELECT * FROM $MIGRATION_TABLE_NAME WHERE BUILD_NUMBER = '$buildNumber'"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Language("TSQL")
|
||||||
|
override fun getInsertMigrationSQL(buildNumber: String, formattedTime: String): String {
|
||||||
|
return """
|
||||||
|
INSERT INTO $MIGRATION_TABLE_NAME (BUILD_NUMBER, DATE)
|
||||||
|
VALUES ('$buildNumber', '$formattedTime');
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.touchin.smartmigration.logic.factory
|
||||||
|
|
||||||
|
import ru.touchin.smartmigration.logic.DataSourceSQL
|
||||||
|
|
||||||
|
interface DataSourceSqlFactory {
|
||||||
|
|
||||||
|
fun getDataSourceSql(driverName: String): DataSourceSQL
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package ru.touchin.smartmigration.logic.factory
|
||||||
|
|
||||||
|
import ru.touchin.smartmigration.logic.DataSourceSQL
|
||||||
|
import ru.touchin.smartmigration.logic.PostgresDataSourceImpl
|
||||||
|
import ru.touchin.smartmigration.logic.SqlDatasourceImpl
|
||||||
|
|
||||||
|
class DataSourceSqlFactoryImpl: DataSourceSqlFactory {
|
||||||
|
|
||||||
|
override fun getDataSourceSql(driverName: String): DataSourceSQL {
|
||||||
|
return when(driverName){
|
||||||
|
"Microsoft SQL Server" -> SqlDatasourceImpl()
|
||||||
|
"PostgresSQL" -> PostgresDataSourceImpl()
|
||||||
|
else -> {
|
||||||
|
PostgresDataSourceImpl()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue