Ciao a tutti. Lascia che te lo ricordi: nella prima parte abbiamo aggiunto Flyway. Continuiamo.
Aggiunta di un database a docker-compose.yml
La fase successiva è l'impostazione del lavoro con il database nel docker-compose.yml principale. Aggiungiamo il database al file docker-compose:version: '3.1'
services:
jrtb-bot:
depends_on:
- jrtb-db
build:
context: .
environment:
BOT_NAME: ${BOT_NAME}
BOT_TOKEN: ${BOT_TOKEN}
BOT_DB_USERNAME: ${BOT_DB_USERNAME}
BOT_DB_PASSWORD: ${BOT_DB_PASSWORD}
restart: always
jrtb-db:
image: mysql:5.7
restart: always
environment:
MYSQL_USER: ${BOT_DB_USERNAME}
MYSQL_PASSWORD: ${BOT_DB_PASSWORD}
MYSQL_DATABASE: 'jrtb_db'
MYSQL_ROOT_PASSWORD: 'root'
ports:
- '3306:3306'
expose:
- '3306'
Ho anche aggiunto questa riga alla nostra applicazione:
depends_on:
- jrtb-db
Ciò significa che aspettiamo l'avvio del database prima di avviare l'applicazione. Successivamente, puoi notare l'aggiunta di altre due variabili di cui abbiamo bisogno per lavorare con il database:
${BOT_DB_USERNAME}
${BOT_DB_PASSWORD}
Li inseriremo in docker-compose allo stesso modo del bot di Telegram, attraverso variabili di ambiente. L'ho fatto in modo da avere un solo posto in cui impostare i valori del nome utente del database e della relativa password. Li passiamo all'immagine docker della nostra applicazione e al contenitore docker del nostro database. Successivamente dobbiamo aggiornare il Dockerfile per insegnare al nostro SpringBoot ad accettare le variabili per il database.
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}", "-Dspring.datasource.username=${BOT_DB_USERNAME}", "-jar", "app.jar"]
Ora aggiungiamo le variabili del database al Dockerfile:
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
I valori delle variabili saranno diversi. Quelli che passeremo nel Dockerfile, però, richiedono valori predefiniti, quindi ne ho inseriti alcuni. Espandiamo l'ultima riga con due elementi, con l'aiuto dei quali passeremo il nome utente e la password del DB all'avvio dell'applicazione:
"-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}"
L'ultima riga nel Dockerfile (che inizia con ENTRYPOINT) deve essere senza ritorno a capo. Se effettui un trasferimento, questo codice non funzionerà. L'ultimo passaggio consiste nell'aggiornare il file start.sh per passare le variabili al database.
#!/bin/bash
# Pull new changes
git pull
# Prepare Jar
mvn clean
mvn package
# Ensure, that docker-compose stopped
docker-compose stop
# Add environment variables
export BOT_NAME=$1
export BOT_TOKEN=$2
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'
# Start new deployment
docker-compose up --build -d
Sappiamo già come aggiungere variabili di ambiente prima di eseguire docker-compose. Per fare ciò, devi solo eseguire export var_name=var_value.. Pertanto, aggiungiamo solo due righe:
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'
Qui è dove impostiamo il nome utente e la password del database. Naturalmente, sarebbe possibile passare queste variabili durante l’esecuzione dello script bash, come facciamo per il nome e il token del bot. Ma mi sembra che questo non sia necessario. Per accedere effettivamente al database, è necessario conoscere l'IP del server su cui verrà distribuito il database ed essere nell'elenco degli indirizzi IP consentiti per la richiesta. Per quanto mi riguarda, questo è già sufficiente. Le basi sono state gettate: ora puoi fare cose più comprensibili per uno sviluppatore: scrivere codice. Prima di ciò, facevamo ciò che fanno gli ingegneri DevOps: configurare l'ambiente.
Aggiunta di un livello di repository
In genere un'applicazione ha tre livelli:- I controller sono i punti di ingresso nell'applicazione.
- I servizi sono il luogo in cui funziona la logica aziendale. In parte lo abbiamo già: SendMessageService è un esplicito rappresentante della logica aziendale.
- I repository sono un luogo in cui lavorare con un database. Nel nostro caso si tratta di un bot di Telegram.
- Non dovremo lavorare con JDBC: lavoreremo direttamente con astrazioni più elevate. Cioè, memorizza i POJO che corrispondono alle tabelle nel database. Chiameremo tali classi entità , come vengono ufficialmente chiamate nell'API Java Persistence (questo è un insieme comune di interfacce per lavorare con un database tramite un ORM, ovvero un'astrazione rispetto al lavoro con JDBC). Avremo una classe di entità che salveremo nel database e verranno scritte esattamente nella tabella di cui abbiamo bisogno. Riceveremo gli stessi oggetti durante la ricerca nel database.
- Spring Data offre di utilizzare il proprio set di interfacce: JpaRepository , CrudRepository , ecc... Esistono altre interfacce: un elenco completo può essere trovato qui . Il bello è che puoi usare i loro metodi senza implementarli (!). Inoltre, esiste un determinato modello in base al quale è possibile scrivere nuovi metodi nell'interfaccia e verranno implementati automaticamente.
- La primavera semplifica il nostro sviluppo il più possibile. Per fare ciò, dobbiamo creare la nostra interfaccia ed ereditare da quelle sopra descritte. E affinché Spring sappia che deve utilizzare questa interfaccia, aggiungi l'annotazione Repository.
- Se dobbiamo scrivere un metodo per lavorare con un database che non esiste, anche questo non è un problema: lo scriveremo. Ti mostrerò cosa e come fare lì.
package com.github.javarushcommunity.jrtb.repository.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
* Telegram User entity.
*/
@Data
@Entity
@Table(name = "tg_user")
public class TelegramUser {
@Id
@Column(name = "chat_id")
private String chatId;
@Column(name = "active")
private boolean active;
}
Qui puoi vedere che abbiamo tutte le annotazioni del pacchetto javax.persistence. Queste sono annotazioni comuni utilizzate per tutte le implementazioni ORM. Per impostazione predefinita, Spring Data Jpa utilizza Hibernate, sebbene sia possibile utilizzare altre implementazioni. Ecco un elenco delle annotazioni che utilizziamo:
- Entità : indica che si tratta di un'entità per lavorare con il database;
- Tabella - qui definiamo il nome della tabella;
- Id : l'annotazione indica quale campo sarà la chiave primaria nella tabella;
- Colonna : determina il nome del campo dalla tabella.
package com.github.javarushcommunity.jrtb.repository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* {@link Repository} for handling with {@link TelegramUser} entity.
*/
@Repository
public interface TelegramUserRepository extends JpaRepository<TelegramUser, String> {
List<TelegramUser> findAllByActiveTrue();
}
Qui puoi vedere come ho aggiunto il metodo findAllByActiveTrue() , che non implemento da nessuna parte. Ma questo non gli impedirà di lavorare. Spring Data capirà che deve ottenere tutti i record dalla tabella tg_user il cui campo attivo = true . Aggiungiamo un servizio per lavorare con l'entità TelegramUser (usiamo l'inversione delle dipendenze da SOLID nel contesto in cui i servizi di altre entità non possono comunicare direttamente con il repository di un'altra entità - solo attraverso il servizio di quell'entità). Creiamo un servizio TelegramUserService nel pacchetto, che per ora avrà diversi metodi: salvare l'utente, ottenere l'utente tramite il suo ID e visualizzare un elenco di utenti attivi. Per prima cosa creiamo l'interfaccia TelegramUserService:
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* {@link Service} for handling {@link TelegramUser} entity.
*/
public interface TelegramUserService {
/**
* Save provided {@link TelegramUser} entity.
*
* @param telegramUser provided telegram user.
*/
void save(TelegramUser telegramUser);
/**
* Retrieve all active {@link TelegramUser}.
*
* @return the collection of the active {@link TelegramUser} objects.
*/
List<TelegramUser> retrieveAllActiveUsers();
/**
* Find {@link TelegramUser} by chatId.
*
* @param chatId provided Chat ID
* @return {@link TelegramUser} with provided chat ID or null otherwise.
*/
Optional<TelegramUser> findByChatId(String chatId);
}
E, infatti, l'implementazione di TelegramUserServiceImpl:
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.repository.TelegramUserRepository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* Implementation of {@link TelegramUserService}.
*/
@Service
public class TelegramUserServiceImpl implements TelegramUserService {
private final TelegramUserRepository telegramUserRepository;
@Autowired
public TelegramUserServiceImpl(TelegramUserRepository telegramUserRepository) {
this.telegramUserRepository = telegramUserRepository;
}
@Override
public void save(TelegramUser telegramUser) {
telegramUserRepository.save(telegramUser);
}
@Override
public List<TelegramUser> retrieveAllActiveUsers() {
return telegramUserRepository.findAllByActiveTrue();
}
@Override
public Optional<TelegramUser> findByChatId(String chatId) {
return telegramUserRepository.findById(chatId);
}
}
Qui va notato che utilizziamo l'iniezione di dipendenza (introduciamo un'istanza di classe) dell'oggetto TelegramuserRepository utilizzando l' annotazione Autowired e sul costruttore. Puoi farlo per una variabile, ma questo è l'approccio consigliato dal team di Spring Framework.
Aggiunta di statistiche per il bot
Successivamente è necessario aggiornare i comandi /start e /stop. Quando viene utilizzato il comando /start, è necessario salvare il nuovo utente nel database e impostarlo su active = true. E quando c'è /stop, aggiorna i dati dell'utente: set active = false. Correggiamo la classe StartCommand :package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;
/**
* Start {@link Command}.
*/
public class StartCommand implements Command {
private final SendBotMessageService sendBotMessageService;
private final TelegramUserService telegramUserService;
public final static String START_MESSAGE = "Привет. Я Javarush Telegram Bot. Я помогу тебе быть в курсе последних " +
"статей тех авторов, котрые тебе интересны. Я еще маленький и только учусь.";
public StartCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
String chatId = update.getMessage().getChatId().toString();
telegramUserService.findByChatId(chatId).ifPresentOrElse(
user -> {
user.setActive(true);
telegramUserService.save(user);
},
() -> {
TelegramUser telegramUser = new TelegramUser();
telegramUser.setActive(true);
telegramUser.setChatId(chatId);
telegramUserService.save(telegramUser);
});
sendBotMessageService.sendMessage(chatId, START_MESSAGE);
}
}
Qui passiamo anche l'oggetto TelegramuserService al costruttore, con il quale salveremo il nuovo utente. Inoltre, sfruttando le delizie dell'Optional in Java, funziona la seguente logica: se abbiamo un utente nel database, lo rendiamo semplicemente attivo, altrimenti ne creiamo uno nuovo attivo. Comando di arresto:
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.Optional;
/**
* Stop {@link Command}.
*/
public class StopCommand implements Command {
private final SendBotMessageService sendBotMessageService;
private final TelegramUserService telegramUserService;
public static final String STOP_MESSAGE = "Деактивировал все ваши подписки \uD83D\uDE1F.";
public StopCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), STOP_MESSAGE);
telegramUserService.findByChatId(update.getMessage().getChatId().toString())
.ifPresent(it -> {
it.setActive(false);
telegramUserService.save(it);
});
}
}
Passiamo TelegramServiceTest a StopCommand allo stesso modo. La logica aggiuntiva è questa: se abbiamo un utente con tale ID chat, lo disattiviamo, cioè impostiamo active = false. Come puoi vederlo con i tuoi occhi? Creiamo un nuovo comando /stat, che visualizzerà le statistiche del bot. In questa fase, queste saranno semplici statistiche a disposizione di tutti gli utenti. In futuro lo limiteremo e renderemo l'accesso solo agli amministratori. Ci sarà una voce nelle statistiche: il numero di utenti bot attivi. A tale scopo, aggiungere il valore STAT("/stat") a CommandName. Successivamente, crea la classe StatCommand :
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.telegram.telegrambots.meta.api.objects.Update;
/**
* Statistics {@link Command}.
*/
public class StatCommand implements Command {
private final TelegramUserService telegramUserService;
private final SendBotMessageService sendBotMessageService;
public final static String STAT_MESSAGE = "Javarush Telegram Bot использует %s человек.";
@Autowired
public StatCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
int activeUserCount = telegramUserService.retrieveAllActiveUsers().size();
sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), String.format(STAT_MESSAGE, activeUserCount));
}
}
Qui tutto è semplice: otteniamo un elenco di tutti gli utenti attivi utilizzando il metodo retrieveAllActiveUsers e otteniamo la dimensione della raccolta. Ora dobbiamo anche aggiornare le classi ascendenti: CommandContainer e JavarushTelegramBot in modo che imparino a trasferire il nuovo servizio di cui abbiamo bisogno. Contenitore comandi:
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import com.google.common.collect.ImmutableMap;
import static com.github.javarushcommunity.jrtb.command.CommandName.*;
/**
* Container of the {@link Command}s, which are using for handling telegram commands.
*/
public class CommandContainer {
private final ImmutableMap<String, Command> commandMap;
private final Command unknownCommand;
public CommandContainer(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
commandMap = ImmutableMap.<String, Command>builder()
.put(START.getCommandName(), new StartCommand(sendBotMessageService, telegramUserService))
.put(STOP.getCommandName(), new StopCommand(sendBotMessageService, telegramUserService))
.put(HELP.getCommandName(), new HelpCommand(sendBotMessageService))
.put(NO.getCommandName(), new NoCommand(sendBotMessageService))
.put(STAT.getCommandName(), new StatCommand(sendBotMessageService, telegramUserService))
.build();
unknownCommand = new UnknownCommand(sendBotMessageService);
}
public Command retrieveCommand(String commandIdentifier) {
return commandMap.getOrDefault(commandIdentifier, unknownCommand);
}
}
Qui abbiamo aggiunto un nuovo comando alla mappa e lo abbiamo passato attraverso il costruttore TelegramUserService. Ma nel bot stesso, cambierà solo il costruttore:
@Autowired
public JavarushTelegramBot(TelegramUserService telegramUserService) {
this.commandContainer = new CommandContainer(new SendBotMessageServiceImpl(this), telegramUserService);
}
Ora passiamo TelegramUserService come argomento, aggiungendo l'annotazione Autowired. Ciò significa che lo riceveremo dal contesto dell'applicazione. Aggiorneremo anche la classe HelpCommand in modo che nella descrizione appaia un nuovo comando statistico.
Test manuale
Lanciamo il database da docker-compose-test.yml e il metodo main nella classe JavarushTelegramBotApplication. Successivamente scriviamo una serie di comandi:- /stat: prevediamo che se il database è vuoto, non ci saranno persone che utilizzeranno questo bot;
- /start - avvia il bot;
- /stat - ora ci aspettiamo che il bot venga utilizzato da 1 persona;
- /stop: ferma il bot;
- /stat - prevediamo che ancora una volta ci saranno 0 persone che lo utilizzeranno.
Scriviamo e aggiorniamo i test
Poiché abbiamo modificato i costruttori, dovremo aggiornare anche le classi di test. Nella classe AbstractCommandTest , dobbiamo aggiungere un altro campo: la classe TelegramUserService , necessaria per tre comandi:protected TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
Successivamente, aggiorniamo il metodo init() in CommandContainer :
@BeforeEach
public void init() {
SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
commandContainer = new CommandContainer(sendBotMessageService, telegramUserService);
}
In StartCommand devi aggiornare il metodo getCommand() :
@Override
Command getCommand() {
return new StartCommand(sendBotMessageService, telegramUserService);
}
Anche in StopCommand:
@Override
Command getCommand() {
return new StopCommand(sendBotMessageService, telegramUserService);
}
Successivamente, diamo un'occhiata ai nuovi test. Creiamo un tipico test per StatCommand :
package com.github.javarushcommunity.jrtb.command;
import static com.github.javarushcommunity.jrtb.command.CommandName.STAT;
import static com.github.javarushcommunity.jrtb.command.StatCommand.STAT_MESSAGE;
public class StatCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return STAT.getCommandName();
}
@Override
String getCommandMessage() {
return String.format(STAT_MESSAGE, 0);
}
@Override
Command getCommand() {
return new StatCommand(sendBotMessageService, telegramUserService);
}
}
Questo è semplice. Ora parliamo di come testeremo il funzionamento con il database. Tutto quello che facevamo prima erano test unitari. Un test di integrazione verifica l'integrazione tra più parti di un'applicazione. Ad esempio, applicazioni e database. Qui tutto sarà più complicato, perché per i test abbiamo bisogno di un database distribuito. Pertanto, quando eseguiamo i nostri test localmente, dobbiamo avere il database in esecuzione da docker-compose-test.yml. Per eseguire questo test, è necessario eseguire l'intera applicazione SpringBoot. La classe test ha un'annotazione SpringBootTest che avvierà l'applicazione. Ma questo approccio non funzionerà per noi, perché quando viene avviata l'applicazione, verrà avviato anche il bot di Telegram. Ma qui c’è una contraddizione. I test verranno eseguiti sia localmente sul nostro computer che pubblicamente tramite GitHub Actions. Affinché i test passino con il lancio dell'intera applicazione, dobbiamo eseguirli con dati validi sul bot di Telegram: cioè con il suo nome e token... Pertanto, abbiamo due opzioni:
- Quindi rendi pubblici il nome e il token del bot e spera che tutto vada bene, nessuno lo userà e interferirà con noi.
- Trova un altro modo.
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
Per noi si troveranno lungo il percorso ./src/test/resources/ + il percorso specificato nell'annotazione. Ecco come appaiono:
clearDbs.sql:
DELETE FROM tg_user;
telegram_users.sql:
INSERT INTO tg_user VALUES ("123456789", 1);
INSERT INTO tg_user VALUES ("123456788", 1);
INSERT INTO tg_user VALUES ("123456787", 1);
INSERT INTO tg_user VALUES ("123456786", 1);
INSERT INTO tg_user VALUES ("123456785", 1);
INSERT INTO tg_user VALUES ("123456784", 0);
INSERT INTO tg_user VALUES ("123456782", 0);
INSERT INTO tg_user VALUES ("123456781", 0);
Questo è come apparirà come risultato il nostro test TelegramUserRepositoryIT (come puoi vedere, il nome per il test di integrazione sarà diverso: aggiungiamo IT, non Test):
package com.github.javarushcommunity.jrtb.repository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import java.util.List;
import java.util.Optional;
import static org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace.NONE;
/**
* Integration-level testing for {@link TelegramUserRepository}.
*/
@ActiveProfiles("test")
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class TelegramUserRepositoryIT {
@Autowired
private TelegramUserRepository telegramUserRepository;
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
@Test
public void shouldProperlyFindAllActiveUsers() {
//when
List<TelegramUser> users = telegramUserRepository.findAllByActiveTrue();
//then
Assertions.assertEquals(5, users.size());
}
@Sql(scripts = {"/sql/clearDbs.sql"})
@Test
public void shouldProperlySaveTelegramUser() {
//given
TelegramUser telegramUser = new TelegramUser();
telegramUser.setChatId("1234567890");
telegramUser.setActive(false);
telegramUserRepository.save(telegramUser);
//when
Optional<TelegramUser> saved = telegramUserRepository.findById(telegramUser.getChatId());
//then
Assertions.assertTrue(saved.isPresent());
Assertions.assertEquals(telegramUser, saved.get());
}
}
Abbiamo scritto i test, ma sorge spontanea la domanda: cosa accadrà con il lancio del nostro processo CI su GitHub? Non avrà un database. Per ora ci sarà davvero solo una build rossa. Per fare ciò, disponiamo di azioni GitHub, in cui possiamo configurare il lancio della nostra build. Prima di eseguire i test, è necessario aggiungere un avvio del database con le impostazioni necessarie. A quanto pare non ci sono molti esempi su Internet, quindi ti consiglio di salvarlo da qualche parte. Aggiorniamo il file .github/workflows/maven.yml:
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up MySQL
uses: mirromutth/mysql-action@v1.1
with:
mysql version: '5.7'
mysql database: 'dev_jrtb_db'
mysql root password: 'root'
mysql user: 'dev_jrtb_db_user'
mysql password: 'dev_jrtb_db_password'
- name: Set up JDK 1.11
uses: actions/setup-java@v1
with:
java-version: 1.11
- name: Build with Maven
run: mvn -B package --file pom.xml
Ora c'è un nuovo blocco Configura MySQL . In esso aggiungiamo MySQL al nostro processo CI, definendo contemporaneamente le variabili di cui abbiamo bisogno. Ora abbiamo aggiunto tutto ciò che volevamo. L'ultima fase è spingere le modifiche e vedere che la build passerà e sarà verde.
Aggiornamento della documentazione
Aggiorniamo la versione del progetto da 0.3.0-SNAPSHOT a 0.4.0-SNAPSHOT in pom.xml e aggiungiamo anche a RELEASE_NOTES:## 0.4.0-SNAPSHOT
* JRTB-1: added repository layer.
Dopo tutto ciò, creiamo una richiesta di commit, push e pull. E, cosa più importante, la nostra costruzione è ecologica!
Link utili:
- Repository del nostro bot di Telegram
- Pull request con tutte le modifiche descritte nell'articolo
- Articolo SpringBoot + Flyway
- Immagine MySQL da DockerHub
- Medio: come creare un'istanza MySql con Docker Compose
- Habr: dati primaverili Jpa
- Il mio canale Telegram
GO TO FULL VERSION