<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Trey Pero</title>
    <description>The latest articles on DEV Community by Trey Pero (@tdpero0516).</description>
    <link>https://dev.to/tdpero0516</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1812122%2F7db3f9a3-1a8f-4a65-93fb-82b3801cb8f3.jpeg</url>
      <title>DEV Community: Trey Pero</title>
      <link>https://dev.to/tdpero0516</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tdpero0516"/>
    <language>en</language>
    <item>
      <title>Agentic IDE: GitHub Copilot App vs Jetbrains Air</title>
      <dc:creator>Trey Pero</dc:creator>
      <pubDate>Sat, 26 Sep 2026 01:49:11 +0000</pubDate>
      <link>https://dev.to/tdpero0516/agentic-ide-github-copilot-app-vs-jetbrains-air-4280</link>
      <guid>https://dev.to/tdpero0516/agentic-ide-github-copilot-app-vs-jetbrains-air-4280</guid>
      <description>&lt;p&gt;As a Java Developer, I spent many years solely using IntelliJ for development. I found it intuitive and it always seemed to have a plugin for every need I could come up with. With the age of AI upon us, I began my journey using Copilot directly in IntelliJ. It was okay, but having a small prompt always felt like it was a second class citizen, so my old habits of going out to google things tended to override the memory that I could just prompt Copilot. &lt;/p&gt;

&lt;p&gt;Eventually I heard about the &lt;a href="https://github.com/features/ai/github-app" rel="noopener noreferrer"&gt;GitHub Copilot App&lt;/a&gt; and was excited at the prospect of having the prompting be the core aspect of the IDE's UI. It was quite the experience. I began with simple things like asking it to run a Spring Boot application for me, or opening swagger docs to get use to it. While these were overall simple things, the Copilot app quickly showed its value. The laptop I was working on didn't have the necessary Java version, so Gradle attempted to download it using the toolchain. The toolchain failed due to cert issues. Traditionally I would have to go mess with my Gradle settings to configure my trust store as needed. Copilot instead noticed the error and downloaded Java separate from the toolchain and configured Gradle to use it, bypassing any manual intervention that may have taken me time and been tedious. I was able to instead jump into development. The swagger docs opened immediately and directly in the IDE, without me having to go lookup the correct path or port and exit my IDE to open it in my browser. Things that previously took several minor, but tedious steps, were automated without having to lift a finger. Conveniently, the IDE included a built-in terminal as well if I wanted to run any commands directly without wasting precious tokens.&lt;/p&gt;

&lt;p&gt;GitHub Copilot App also supported writing "Automations". Reusable prompts that could be scheduled or manually triggered. I found this helpful to perform some operations like fetching and pruning branches from my git repos, reporting on PRs opened by bulk automation that needed reviewed, etc.&lt;/p&gt;

&lt;p&gt;As I began to experiment with bigger things like describing full GitHub Action workflows and having it write them for me, developing AI skills, or doing large scale refactoring, I found myself frustrated that viewing the actual contents of the codebase was not as simple as it was before. While I wanted the prompting to be more "front and center" I didn't necessarily want to lose the ability to go view the codebase or modify it manually if I needed to be able to. I would tend to keep IntelliJ open in the background for this, which was not helpful as they ran in different contexts. The GitHub Copilot App would create &lt;a href="https://git-scm.com/docs/git-worktree" rel="noopener noreferrer"&gt;git worktrees&lt;/a&gt; for sessions and if I needed to be able to modify something manually, I would be on an entirely different branch in IntelliJ. Coordinating these kinds of changes became tedious and inconvenient. &lt;/p&gt;

&lt;p&gt;More recently I found out about &lt;a href="https://www.jetbrains.com/air/" rel="noopener noreferrer"&gt;JetBrains Air&lt;/a&gt;, a new IDE from the makers of IntelliJ. Similar in concept to the GitHub Copilot App, Air puts the prompt front and center using the typical JetBrains look and feel that I was use to from IntelliJ for so many years. This was an appealing concept, so I jumped right into my JetBrains Toolbox and installed it. Air offered multiple providers such as Claude, Gemini, etc. While Copilot wasn't on the list out of the box, I was able to make a small change to my acp.json to add it. One of the first things I noticed about the UI was how simple it looked. There wasn't a whole lot going on, which was definitely a contrast to IntelliJ. But in the top right was a game changer. A "Files" icon. I clicked it and began opening contents of my codebase, something I was unable to do from the GitHub Copilot App. While I want the prompting to be the first class citizen and easy to use, it's nice to have the ability to view and manually modify the code myself whenever I need. I found this to be a really helpful balance between the two capabilities.&lt;/p&gt;

&lt;p&gt;JetBrains Air seemed to provide everything I wanted from the GitHub Copilot App. First class prompting, scheduling automations, terminal access, manual viewing/editing of the codebase, etc. The only downside I noticed was the automations could only be created/modified from a separate web view. I would prefer to be able to do this directly in the IDE, but hopefully this is something that will be added in the future. &lt;/p&gt;

&lt;p&gt;I really like both applications, but I believe I'll be switching to JetBrains Air for my agentic development workflow. Between the balance of prompting and manual coding and the flexibility to configure my AI provider, I think it will meet my needs better. Certainly doesn't help that the look and feel aligns with what I've been use to for many years. Given it's in public preview I also look forward to how it may evolve in the future with the potential for various JetBrains plugins. &lt;/p&gt;

&lt;p&gt;What are your thoughts? Do you prefer Copilot App or JetBrains Air? Do you prefer something else? Drop a comment!&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>github</category>
      <category>java</category>
    </item>
    <item>
      <title>Level up your Karate Testing with Spring Boot DI</title>
      <dc:creator>Trey Pero</dc:creator>
      <pubDate>Mon, 22 Jul 2024 02:36:19 +0000</pubDate>
      <link>https://dev.to/tdpero0516/level-up-your-karate-testing-with-spring-boot-di-42em</link>
      <guid>https://dev.to/tdpero0516/level-up-your-karate-testing-with-spring-boot-di-42em</guid>
      <description>&lt;p&gt;For a few years I've used Cucumber for higher level testing, and only more recently started using &lt;a href="https://github.com/karatelabs/karate" rel="noopener noreferrer"&gt;Karate&lt;/a&gt;. While Cucumber is a great tool, I think Karate really shines in reducing the boilerplate that comes along with step definitions and making it easy to write meaningful tests quickly, especially when it comes to API testing.&lt;/p&gt;

&lt;p&gt;For simple applications, writing your feature files in plain JavaScript will suffice. As your application and tests grow, reusing some Java code can become valuable though. Spring Boot APIs can benefit a lot from Karate testing, but what about leveraging the power of Spring Boot directly in your Karate tests?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some example use cases&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While Karate supports configuration via karate-config.js files, some may like configuring via Spring YAML/properties instead. This can be helpful to reconfigure things outside of rebuilding code as well.&lt;/li&gt;
&lt;li&gt;To sync certain Spring Boot configuration properties between application and tests.&lt;/li&gt;
&lt;li&gt;To verify database state between API calls. JPA repository/entity beans could be used in the Karate tests.&lt;/li&gt;
&lt;li&gt;Some Spring beans may simply be useful to utilize in tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How to integrate Spring into Karate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Full sample project: &lt;a href="https://github.com/trey-pero/karate-spring" rel="noopener noreferrer"&gt;https://github.com/trey-pero/karate-spring&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Karate can be executed via a simple JUnit test. To begin wiring Spring in, setup the JUnit test as a @SpringBootTest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RequiredArgsConstructor
@SpringBootTest(classes = Main.class)
public class KarateTest {
    private final ApplicationContext applicationContext;

    @Test
    void test() {
        ApplicationContextHolder.setApplicationContext(this.applicationContext);

        // Since this one JUnit test runs all Karate tests,
        // fail the test if any underlying Karate tests fail
        assertEquals(0, Runner.path("classpath:org/tpero")
                .parallel(Optional.ofNullable(System.getProperty("karate.threads"))
                        .map(Integer::parseInt)
                        .orElse(5)
                ).getFailCount());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to access the Spring context (which provides access to all beans and configuration), it needs to be stored somewhere that Karate can access it statically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Provides Karate static access to the Spring application context.
 */
@UtilityClass
public class ApplicationContextHolder {
    @Setter
    @Getter
    private ApplicationContext applicationContext;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From Karate config, the static holder can be accessed to wire the application context into Karate's global configuration map using the following sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Define common feature file configuration here.
 * @returns Common configuration as a JSON object.
 */
function getConfig() {
    // Global values
    const appContext = Java.type("org.tpero.ApplicationContextHolder")
        .getApplicationContext()
    const environment = appContext.getEnvironment()

    return {
        appContext: appContext,
        environment: environment,

        baseUrl: `http://localhost:${environment.getProperty('app.server.port', '8080')}`
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above setup code, beans and configuration can be accessed from Karate feature files, shown by this sample which tests a simple login API that returns a JWT token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature: Login
  Background:
    * url baseUrl
    * path '/login'
    # Load the JWT service bean from Spring DI
    * def jwtService = appContext.getBean('jwtService')

  Scenario: Login with valid credentials
    Given request { username: 'user', password: 'password' }
    When method post
    Then status 200
    * print response

    # Use the JWT service bean to decode the JWT from the response
    * def decodedJwt = jwtService.decode(response)
    * print decodedJwt
    * def decodedBody = decodedJwt.getBody()
    * print decodedBody

    And match decodedBody['sub'] == 'user'
    * def issuedAt = Number(decodedBody['iat'])
    # Ensure the issuedAt is in the past
    And assert issuedAt &amp;lt; Java.type('java.lang.System').currentTimeMillis()
    * def configuredExpirationInMinutes = Number(environment.getProperty('jwt.expiration.ms')) / 1000
    # Ensure the expiration is the configurable amount of minutes beyond the issuedAt
    And match Number(decodedBody['exp']) == issuedAt + configuredExpirationInMinutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sample demonstrates how easy it is to integrate the power of Spring Boot into Karate to build more capable test suites. &lt;/p&gt;

</description>
      <category>karate</category>
      <category>springboot</category>
      <category>java</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
