EPMRPP-114079 || add SQL script to restore GitHub integration#4
Conversation
…ckup and update GitHubExtension to initialize schema
WalkthroughAdds lifecycle-managed plugin load handling and schema initialization: a PluginLoadedEventListener executes SQL scripts against a DataSource on plugin upload; GitHubExtension now registers/unregisters that listener and exposes init() throwing IOException; new PluginInfoProvider and implementation supply integration metadata; a DB migration restores GitHub integrations. Changes
Sequence Diagram(s)sequenceDiagram
participant Multicaster as ApplicationEventMulticaster
participant Extension as GitHubExtension
participant Listener as PluginLoadedEventListener
participant DB as DataSource/JdbcTemplate
participant Repo as IntegrationTypeRepository
Note over Extension,Multicaster: Startup / plugin lifecycle
Extension->>Multicaster: register(Listener)
Multicaster-->>Extension: registered
Note over Listener,Repo: On PluginUploadedEvent
Multicaster->>Listener: PluginUploadedEvent(pluginName)
Listener->>Listener: if pluginName matches pluginId
Listener->>Repo: query IntegrationType (for metadata)
Listener->>DB: for each discovered SQL script -> execute(sql)
DB-->>Listener: execution result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/main/java/com/epam/reportportal/extension/github/GitHubExtension.java (1)
145-145: Avoid replaying every numbered script on each startup.This initializer has no migration history, so every boot re-executes every file under
schema/. That only stays safe while every script is perfectly idempotent; the first normal migration will turn startup into a deployment-time failure point. Please back this with Flyway/Liquibase or store an applied-script marker before adding more numbered scripts.Also applies to: 218-224
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/epam/reportportal/extension/github/GitHubExtension.java` at line 145, The initSchema() call currently re-runs every numbered script under schema/ on each startup (no migration history), so change initSchema() to use a proper migration mechanism: either integrate Flyway or Liquibase to track applied migrations (e.g., use Flyway.configure().dataSource(...).migrate()) or implement an applied-script marker (a persistent table like schema_version and record each applied filename/checksum) and have initSchema() check that marker before executing a script; update any other schema initialization calls that execute scripts (the same initSchema() invocation and related boot-time schema loader) to rely on the migration history so scripts are not replayed on every boot.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/com/epam/reportportal/extension/github/GitHubExtension.java`:
- Line 126: resourcesDir is never initialized and initSchema() uses
Paths.get(resourcesDir, "schema") which causes NPE and fails to load SQL
packaged in the JAR; remove the unused resourcesDir field and change
initSchema()/init() to load schema files from the classpath using Spring's
PathMatchingResourcePatternResolver (or ResourcePatternResolver) with the
pattern "classpath*:schema/*.sql" instead of Files.list/FileSystemResource, then
iterate the returned Resource[] to read and execute the scripts (update any
references to Paths.get(resourcesDir, "schema") and ensure `@PostConstruct` init()
calls the new initSchema() implementation).
In `@src/main/resources/schema/001_restore_github_integration.sql`:
- Around line 7-20: The INSERT SELECT is pulling every row from
integration_backup and inserting them as GitHub integrations; add a WHERE clause
to the SELECT to match the DELETE predicate (filter integration_backup ib with
ib.name = 'github' AND ib.auth_type = 'OAUTH') and remove the ineffective "ON
CONFLICT (id) DO NOTHING" clause so the INSERT INTO integration ... SELECT ...
FROM integration_backup ib WHERE ... only migrates the intended GitHub/OAUTH
backup rows; update the INSERT statement that references integration,
integration_type subquery, ib.params, 'SYSTEM', now(), true and the DELETE that
follows will then correctly remove the same filtered rows.
---
Nitpick comments:
In `@src/main/java/com/epam/reportportal/extension/github/GitHubExtension.java`:
- Line 145: The initSchema() call currently re-runs every numbered script under
schema/ on each startup (no migration history), so change initSchema() to use a
proper migration mechanism: either integrate Flyway or Liquibase to track
applied migrations (e.g., use Flyway.configure().dataSource(...).migrate()) or
implement an applied-script marker (a persistent table like schema_version and
record each applied filename/checksum) and have initSchema() check that marker
before executing a script; update any other schema initialization calls that
execute scripts (the same initSchema() invocation and related boot-time schema
loader) to rely on the migration history so scripts are not replayed on every
boot.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a9870cfe-7e4f-4eb4-8a41-5f62428a3e9c
📒 Files selected for processing (2)
src/main/java/com/epam/reportportal/extension/github/GitHubExtension.javasrc/main/resources/schema/001_restore_github_integration.sql
…d PluginInfoProvider implementation
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java (1)
85-87: Prefer Spring SQL script utilities over rawJdbcTemplate.execute(sql).Executing full file text directly is brittle for multi-statement scripts, separators, and comments. Use
ScriptUtils.executeSqlScript(...)orResourceDatabasePopulatorfor robust parsing/execution.Proposed refactor
+import org.springframework.jdbc.datasource.init.ScriptUtils; ... - try (InputStream is = r.getInputStream()) { - String sql = new String(is.readAllBytes(), StandardCharsets.UTF_8); - jdbcTemplate.execute(sql); - } + ScriptUtils.executeSqlScript(jdbcTemplate.getDataSource().getConnection(), r);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java` around lines 85 - 87, Replace the brittle raw execution of the SQL file in PluginLoadedEventListener (currently reading r.getInputStream() into a String and calling jdbcTemplate.execute(sql)) with Spring's SQL script utilities: load the Resource (r) and run ScriptUtils.executeSqlScript or use a ResourceDatabasePopulator to execute the script against the DataSource/jdbcTemplate so multi-statement scripts, comments and separators are handled correctly; ensure to pass the proper Connection or DataSource and handle SQLExceptions similarly to the existing try-with-resources.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java`:
- Around line 77-80: The GitHub schema init currently only logs at debug and
returns silently when resources.length == 0; update PluginLoadedEventListener
(the block that logs "GitHub schema init: found {} script(s)") to emit a warning
via log.warn(...) just before returning when no SQL scripts are found
(resources.length == 0), including contextual text that indicates schema scripts
were not discovered (mention resources/classpath or migration scripts) so
missing scripts are visible in production logs.
- Around line 82-89: The schema initialization in
PluginLoadedEventListener.initSchema currently executes resources (Resource r)
via a JdbcTemplate without transaction management; wrap the entire loop in a
single transaction using a TransactionTemplate constructed with a
DataSourceTransactionManager (or use PlatformTransactionManager) so all SQL from
resources are executed atomically and roll back on failure; create
TransactionTemplate tx = new TransactionTemplate(new
DataSourceTransactionManager(dataSource)) (or inject the
PlatformTransactionManager), then run tx.execute(status -> { for (Resource r :
resources) { read bytes, jdbcTemplate.execute(sql); } return null; }) to ensure
atomicity and proper rollback.
In
`@src/main/java/com/epam/reportportal/extension/github/info/impl/PluginInfoProviderImpl.java`:
- Around line 42-44: PLUGIN_DESCRIPTION in PluginInfoProviderImpl currently
mentions Jira Cloud; update the constant's string to accurately describe the
GitHub integration (e.g., exchange of issue creation/linking and status updates
between ReportPortal and GitHub) so plugin metadata reflects GitHub rather than
Jira. Locate the PLUGIN_DESCRIPTION constant in the PluginInfoProviderImpl class
and replace the Jira-specific wording with GitHub-specific wording that matches
the plugin's functionality.
---
Nitpick comments:
In
`@src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java`:
- Around line 85-87: Replace the brittle raw execution of the SQL file in
PluginLoadedEventListener (currently reading r.getInputStream() into a String
and calling jdbcTemplate.execute(sql)) with Spring's SQL script utilities: load
the Resource (r) and run ScriptUtils.executeSqlScript or use a
ResourceDatabasePopulator to execute the script against the
DataSource/jdbcTemplate so multi-statement scripts, comments and separators are
handled correctly; ensure to pass the proper Connection or DataSource and handle
SQLExceptions similarly to the existing try-with-resources.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 41d96d95-d44c-4b5d-bc90-cfe9ecd5a4bc
📒 Files selected for processing (5)
src/main/java/com/epam/reportportal/extension/github/GitHubExtension.javasrc/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.javasrc/main/java/com/epam/reportportal/extension/github/info/PluginInfoProvider.javasrc/main/java/com/epam/reportportal/extension/github/info/impl/PluginInfoProviderImpl.javasrc/main/resources/schema/001_restore_github_integration.sql
✅ Files skipped from review due to trivial changes (1)
- src/main/resources/schema/001_restore_github_integration.sql
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/com/epam/reportportal/extension/github/GitHubExtension.java
| log.debug("GitHub schema init: found {} script(s)", resources.length); | ||
| if (resources.length == 0) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== SCHEMA_SCRIPTS_DIR definition =="
fd -i 'GitHubExtension.java' --exec sh -c 'echo "--- $1"; sed -n "1,220p" "$1"' sh {}
echo
echo "== SQL resources present in repository =="
fd -i '\.sql$'Repository: reportportal/plugin-auth-github
Length of output: 8825
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find and read the PluginLoadedEventListener.java file
fd -i 'PluginLoadedEventListener.java' --exec cat -n {} \;Repository: reportportal/plugin-auth-github
Length of output: 4331
Emit a warning log when no schema scripts are found.
The current code returns silently on line 79 with only a debug-level log when resources.length == 0. In production deployments where debug logging is disabled, this masks potential issues like broken classpath patterns or failed resource packaging, causing database migrations to be skipped without any indication. Add a log.warn() call when zero SQL scripts are discovered to ensure deployment problems are visible.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java`
around lines 77 - 80, The GitHub schema init currently only logs at debug and
returns silently when resources.length == 0; update PluginLoadedEventListener
(the block that logs "GitHub schema init: found {} script(s)") to emit a warning
via log.warn(...) just before returning when no SQL scripts are found
(resources.length == 0), including contextual text that indicates schema scripts
were not discovered (mention resources/classpath or migration scripts) so
missing scripts are visible in production logs.
| JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); | ||
| for (Resource r : resources) { | ||
| log.info("GitHub schema init: executing {}", r.getFilename()); | ||
| try (InputStream is = r.getInputStream()) { | ||
| String sql = new String(is.readAllBytes(), StandardCharsets.UTF_8); | ||
| jdbcTemplate.execute(sql); | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and examine the file
find . -name "PluginLoadedEventListener.java" -type fRepository: reportportal/plugin-auth-github
Length of output: 175
🏁 Script executed:
# Also search for any transaction-related configuration or usage
rg -i "transactionmanager|transactiontemplate|@transactional" --type java | head -20Repository: reportportal/plugin-auth-github
Length of output: 170
🏁 Script executed:
# Check for migration tools usage
rg -i "flyway|liquibase" --type javaRepository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Check for existing Spring configuration or DataSource management
rg "DataSource|JdbcTemplate" --type java -B 2 -A 2 | head -40Repository: reportportal/plugin-auth-github
Length of output: 4518
🏁 Script executed:
# Let's examine the actual file to see the full context of the initSchema method
cat -n src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java | sed -n '70,100p'Repository: reportportal/plugin-auth-github
Length of output: 1178
🏁 Script executed:
# Check what method this is part of and the full context
cat -n src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java | sed -n '60,110p'Repository: reportportal/plugin-auth-github
Length of output: 1511
🏁 Script executed:
# Let's also check if there's a PlatformTransactionManager bean configured in the project
rg "PlatformTransactionManager|TransactionManager" --type javaRepository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Check the Spring version and available transaction dependencies
fd "pom.xml|build.gradle" -type f | head -5Repository: reportportal/plugin-auth-github
Length of output: 245
🏁 Script executed:
# Find the build configuration files
find . -maxdepth 2 -name "pom.xml" -o -name "build.gradle"Repository: reportportal/plugin-auth-github
Length of output: 89
🏁 Script executed:
# Let's check the pom.xml to see Spring version and transaction dependencies
head -100 pom.xmlRepository: reportportal/plugin-auth-github
Length of output: 141
🏁 Script executed:
# Check if there's a PlatformTransactionManager configured anywhere
rg "PlatformTransactionManager|TransactionManager|@EnableTransactionManagement" --type javaRepository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Let's also check how the onApplicationEvent method is called - is it in a transaction context?
cat -n src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java | head -100Repository: reportportal/plugin-auth-github
Length of output: 4331
🏁 Script executed:
# Check the build.gradle for dependencies
cat build.gradleRepository: reportportal/plugin-auth-github
Length of output: 3687
🏁 Script executed:
# Search for transaction management in the broader codebase
rg "TransactionTemplate|DataSourceTransactionManager" --type javaRepository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Check if there's a test or configuration that shows how initSchema should behave
rg "initSchema" --type java -B 3 -A 3Repository: reportportal/plugin-auth-github
Length of output: 1932
🏁 Script executed:
# Check if PlatformTransactionManager is configured in the Spring context
rg "PlatformTransactionManager|TransactionManager|@EnableTransactionManagement|@Bean" --type java -A 2Repository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Let's check if there's any Spring configuration class that sets up transaction management
find . -name "*Config*" -type f | head -10Repository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Check the schema files to understand the complexity of the migrations
find . -name "*.sql" -type f 2>/dev/nullRepository: reportportal/plugin-auth-github
Length of output: 137
🏁 Script executed:
# Check if there's any existing issue or comment in the codebase about transactions for schema init
rg -i "schema|migration|transaction" --type java src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java -B 2 -A 2Repository: reportportal/plugin-auth-github
Length of output: 1100
🏁 Script executed:
# Check if `@Transactional` could be used instead - verify transaction manager availability
rg "spring.jpa.hibernate|spring.datasource|DataSourceAutoConfiguration" --type propertiesRepository: reportportal/plugin-auth-github
Length of output: 109
🏁 Script executed:
# Look for any Spring Boot auto-configuration or transaction setup
find . -name "application*.properties" -o -name "application*.yml"Repository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Check for Spring configuration files
find . -name "*.properties" -o -name "*.yml" -o -name "*.yaml"Repository: reportportal/plugin-auth-github
Length of output: 316
🏁 Script executed:
# Look for Spring Bean configuration
rg "@Configuration|@EnableTransactionManagement|transactionManager" --type javaRepository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Check if JdbcTemplate with DataSource auto-configures a transaction manager in Spring Boot
rg "class.*Configuration|@Bean" --type java -A 5 | head -40Repository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Let's check the schema file to understand what operations are being performed
cat src/main/resources/schema/001_restore_github_integration.sqlRepository: reportportal/plugin-auth-github
Length of output: 986
🏁 Script executed:
# Check if Spring Boot's auto-configuration includes transaction support for JdbcTemplate
rg "DataSourceTransactionManager|transactionManager" src/main --type javaRepository: reportportal/plugin-auth-github
Length of output: 57
🏁 Script executed:
# Verify Spring version and check if auto-configuration applies
cat build.gradle | grep -i "spring-boot"Repository: reportportal/plugin-auth-github
Length of output: 150
Wrap schema initialization in a single database transaction to ensure atomicity.
The initSchema() method executes SQL scripts without transaction management. Even the single schema file contains multiple operations (INSERT, DELETE, DROP TABLE) that should be atomic—if any operation fails midway, the database is left in a partially applied state. Wrap the script execution loop in a transaction using TransactionTemplate with DataSourceTransactionManager.
Proposed fix (transaction wrapper)
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.support.TransactionTemplate;
...
public void initSchema() {
...
- JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
- for (Resource r : resources) {
- log.info("GitHub schema init: executing {}", r.getFilename());
- try (InputStream is = r.getInputStream()) {
- String sql = new String(is.readAllBytes(), StandardCharsets.UTF_8);
- jdbcTemplate.execute(sql);
- }
- }
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+ TransactionTemplate tx = new TransactionTemplate(new DataSourceTransactionManager(dataSource));
+ tx.executeWithoutResult(status -> {
+ for (Resource r : resources) {
+ log.info("GitHub schema init: executing {}", r.getFilename());
+ try (InputStream is = r.getInputStream()) {
+ String sql = new String(is.readAllBytes(), StandardCharsets.UTF_8);
+ jdbcTemplate.execute(sql);
+ } catch (Exception e) {
+ status.setRollbackOnly();
+ throw new IllegalStateException("Failed to execute schema script: " + r.getFilename(), e);
+ }
+ }
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); | |
| for (Resource r : resources) { | |
| log.info("GitHub schema init: executing {}", r.getFilename()); | |
| try (InputStream is = r.getInputStream()) { | |
| String sql = new String(is.readAllBytes(), StandardCharsets.UTF_8); | |
| jdbcTemplate.execute(sql); | |
| } | |
| } | |
| JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); | |
| TransactionTemplate tx = new TransactionTemplate(new DataSourceTransactionManager(dataSource)); | |
| tx.executeWithoutResult(status -> { | |
| for (Resource r : resources) { | |
| log.info("GitHub schema init: executing {}", r.getFilename()); | |
| try (InputStream is = r.getInputStream()) { | |
| String sql = new String(is.readAllBytes(), StandardCharsets.UTF_8); | |
| jdbcTemplate.execute(sql); | |
| } catch (Exception e) { | |
| status.setRollbackOnly(); | |
| throw new IllegalStateException("Failed to execute schema script: " + r.getFilename(), e); | |
| } | |
| } | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/main/java/com/epam/reportportal/extension/github/event/listener/PluginLoadedEventListener.java`
around lines 82 - 89, The schema initialization in
PluginLoadedEventListener.initSchema currently executes resources (Resource r)
via a JdbcTemplate without transaction management; wrap the entire loop in a
single transaction using a TransactionTemplate constructed with a
DataSourceTransactionManager (or use PlatformTransactionManager) so all SQL from
resources are executed atomically and roll back on failure; create
TransactionTemplate tx = new TransactionTemplate(new
DataSourceTransactionManager(dataSource)) (or inject the
PlatformTransactionManager), then run tx.execute(status -> { for (Resource r :
resources) { read bytes, jdbcTemplate.execute(sql); } return null; }) to ensure
atomicity and proper rollback.
| private static final String PLUGIN_DESCRIPTION = | ||
| "The integration provides an exchange of information between ReportPortal and the Jira Cloud, such as posting issues and linking issues, getting updates on their statuses."; | ||
|
|
There was a problem hiding this comment.
Incorrect integration description references Jira instead of GitHub.
PLUGIN_DESCRIPTION on Line 43 describes Jira Cloud, which is inconsistent for the GitHub plugin and will surface incorrect metadata to users.
Proposed fix
- private static final String PLUGIN_DESCRIPTION =
- "The integration provides an exchange of information between ReportPortal and the Jira Cloud, such as posting issues and linking issues, getting updates on their statuses.";
+ private static final String PLUGIN_DESCRIPTION =
+ "The integration provides an exchange of information between ReportPortal and GitHub, such as posting issues, linking issues, and getting updates on their statuses.";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/main/java/com/epam/reportportal/extension/github/info/impl/PluginInfoProviderImpl.java`
around lines 42 - 44, PLUGIN_DESCRIPTION in PluginInfoProviderImpl currently
mentions Jira Cloud; update the constant's string to accurately describe the
GitHub integration (e.g., exchange of issue creation/linking and status updates
between ReportPortal and GitHub) so plugin metadata reflects GitHub rather than
Jira. Locate the PLUGIN_DESCRIPTION constant in the PluginInfoProviderImpl class
and replace the Jira-specific wording with GitHub-specific wording that matches
the plugin's functionality.
Summary by CodeRabbit
New Features
Chores