CINXE.COM
The JetBrains Blog
<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" > <channel> <title>The JetBrains Blog</title> <atom:link href="https://blog.jetbrains.com/feed/" rel="self" type="application/rss+xml" /> <link>https://blog.jetbrains.com</link> <description>Developer Tools for Professionals and Teams</description> <lastBuildDate>Tue, 26 Nov 2024 13:52:49 +0000</lastBuildDate> <language>en-US</language> <sy:updatePeriod> hourly </sy:updatePeriod> <sy:updateFrequency> 1 </sy:updateFrequency> <image> <url>https://blog.jetbrains.com/wp-content/uploads/2024/01/cropped-mstile-310x310-1-32x32.png</url> <title>The JetBrains Blog</title> <link>https://blog.jetbrains.com</link> <width>32</width> <height>32</height> </image> <item> <title>Kotlin Roundup: Kodee’s Top Picks</title> <link>https://blog.jetbrains.com/kotlin/2024/11/kotlin-roundup-kodee-s-top-picks/</link> <dc:creator><![CDATA[Kodee]]></dc:creator> <pubDate>Tue, 26 Nov 2024 09:09:14 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/1.png</featuredImage> <category><![CDATA[news]]></category> <category><![CDATA[kotlin-news]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=kotlin&p=529940</guid> <description><![CDATA[Hi everyone! Time flies, doesn’t it? It’s already my second edition of Kotlin Roundup, and I can’t wait to share the latest from the Kotlin ecosystem. Did you know that the JetBrains team regularly publishes a newsletter featuring major Kotlin ecosystem news? Sign up to stay up to date with all things Kotlin.]]></description> <content:encoded><![CDATA[ <p>Hi everyone! Time flies, doesn’t it? It’s already my second edition of Kotlin Roundup, and I can’t wait to share the latest from the Kotlin ecosystem.</p> <div class="newsletter"> <h2>Kotlin highlights</h2> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Twitter-1200x675-1.png" alt="Kotlin is the fifth-fastest-growing language on GitHub"> <div class="newsletter__post-text"> <h3>🎉 Kotlin is the fifth-fastest-growing language on GitHub</h3> <p>I was recently reading this year’s <a href="https://github.blog/news-insights/octoverse/octoverse-2024/#the-most-popular-programming-languages" target="_blank" rel="noopener">Octoverse report</a>, and I was blown away by the news. Kotlin is one of the top five fastest-growing languages on GitHub! This wouldn’t be possible without your help. To all the developers, contributors, and advocates, thank you for your passion, dedication, and belief in Kotlin.</p> </div> </article> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/10/Featured_1280x720-2x-1.png" alt="Ktor 3.0 comes with new features and improved performance"> <div class="newsletter__post-text"> <h3>Ktor 3.0 comes with new features and improved performance</h3> <p>In case you missed it, we released Ktor 3.0, which is packed with awesome upgrades! It now uses Kotlin 2.0 and the new kotlinx-io library for next-level performance and better integration with other Kotlin tools. Oh, and did I mention it also includes support for server-sent events (SSE), the ability to serve static resources straight from ZIP archives, and WebAssembly support for the Ktor client? Time to supercharge your projects! 🚀 We’ve also prepared a <a href="https://ktor.io/docs/migrating-3.html" target="_blank" rel="noopener">migration guide</a> from the 2.2.x version to 3.0.x to make the transition easier.</p> <a href="https://blog.jetbrains.com/kotlin/2024/10/ktor-3-0/" class="btn" target="_blank">Explore 3.0 in detail</a> </div> </article> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/2.1.0-RC.jpeg" alt="The Kotlin 2.1.0-RC2 release"> <div class="newsletter__post-text"> <h3>The Kotlin 2.1.0-RC2 release</h3> <p>Big news: Kotlin 2.1.0 is just around the corner – so close, you can almost touch it! But if you’re too excited to wait, Kotlin 2.1.0-RC2 is here to give you an early taste of what’s coming. 🌟 You can preview shiny new language features, try out the Kotlin/Wasm incremental compilation, and enjoy an improved K2 kapt implementation. We’ve also updated LLVM from version 11.1.0 to 16.0.0 for Kotlin/Native. Plus, there are some nice Compose compiler improvements.</p> <a href="https://kotlinlang.org/docs/whatsnew-eap.html" class="btn" target="_blank" rel="noopener">Take a closer look</a> </div> </article> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Livestream-2.1.jpg" alt="Kotlin 2.1 livestream with the Language Evolution team"> <div class="newsletter__post-text"> <h3>Kotlin 2.1 livestream with the Language Evolution team</h3> <p>Ready to see Kotlin 2.1 in action? Join us live on November 28 as the Language Evolution team takes you through exciting new features like non-local break and continue, enhanced function overload resolution, and multidollar interpolation. Have some questions? Bring ‘em on! My good friends <a href="https://serranofp.com/" target="_blank" rel="noopener">Alejandro</a>, <a href="https://x.com/MZarechenskiy" target="_blank">Mikhail</a>, and <a href="https://x.com/antonarhipov" target="_blank">Anton</a> will answer whatever you’ve got to ask, and they’ll also give you a sneak peek at what’s coming next.</p> <a href="https://info.jetbrains.com/kotlin-livestream-november28-2024.html" class="btn" target="_blank" rel="noopener">Join us live</a> </div> </article> </div> <div style="background-color: #f1f6fe; margin-bottom: 2px; padding: 5px; margin-right: 0%; text-align: left; min-height: px;"> <p>Did you know that the JetBrains team regularly publishes a newsletter featuring major Kotlin ecosystem news? <a href="https://info.jetbrains.com/kotlin-communication-center-page.html" target="_blank" rel="noreferrer noopener"><em>Sign up to stay up to date with all things Kotlin.</em></a></p> </div> <p></p> <div class="newsletter"> <h2>KotlinConf 2025</h2> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Call-for-speakers.jpg" alt="Call for KotlinConf 2025 speakers"> <div class="newsletter__post-text"> <h3>🚨 Last call for KotlinConf 2025 speakers</h3> <p>Do you have something interesting to share? Whether it’s related to the server side, Kotlin Multiplatform, AI, or your best practices, we want to hear from YOU! This is your moment to inspire and connect with the Kotlin community at the biggest Kotlin event of the year. 🌟 Don’t miss your chance to make an impact!</p> <a href="https://kotl.in/conf-cfp-2025" class="btn" target="_blank" rel="noopener">Submit your talk</a> </div> </article> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/KotlinConf-tickets.png" alt="Get your KotlinConf 2025 ticket and meet Kodee"> <div class="newsletter__post-text"> <h3>🎟️ Get your KotlinConf 2025 ticket (Kodee’s waiting for you!)</h3> <p>KotlinConf is coming to <span style="color:rgb(127, 82, 255);"><s>K</s>Copenhagen</span>, May 21–23, 2025, and it’s going to be huge! With 2,500 developers gathered to explore server-side, web, mobile, and desktop Kotlin, this is the place to be. Join us for jam-packed days of sessions, workshops, and networking with the brightest minds in the industry. Tickets are going fast, so grab yours before they’re gone!</p> <p>A certain purple plushie <i>can’t</i> wait to meet you there! 😉💜</p> <a href="https://kotl.in/conf-tickets-2025" class="btn" target="_blank" rel="noopener">Secure your spot</a> </div> </article> </div> <div class="newsletter"> <h2>Kotlin Multiplatform</h2> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/09/Blog-Featured-1280x720-1.png" alt="Kotlin Multiplatform Contest 2025"> <div class="newsletter__post-text"> <h3>Kotlin Multiplatform Contest</h3> <p>If you’re a <b>student or recent graduate</b> with fresh coding skills or a creative project idea, this is your chance to show off and win a trip to KotlinConf 2025! Create some cross-platform magic with Kotlin Multiplatform, and who knows – you might just find yourself joining us (me included) in Copenhagen! 🤩</p> <a href="https://kotl.in/conf-contest-2025" class="btn" target="_blank" rel="noopener">Join the contest now</a> </div> </article> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/KMP-video.jpg" alt="Leading Companies Build with Kotlin Multiplatform (KMP)"> <div class="newsletter__post-text"> <h3>🎥 Leading companies build with Kotlin Multiplatform – video </h3> <p>Want to know how big names like Bolt, Philips, McDonald’s, and Wrike streamline their iOS and Android development? They use Kotlin Multiplatform and Compose Multiplatform to save time and build apps across both platforms. In our latest video, you’ll hear firsthand from these teams about how they use the power of Kotlin to elevate their development process. Grab some popcorn and enjoy! 🍿</p> <a href="https://www.youtube.com/watch?v=Qu3jZX8RyFk" class="btn" target="_blank" rel="noopener">Jump to the video </a> </div> </article> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/10/Featured_1280x720-2x-2.png" alt="Kotlin Multiplatform Development Roadmap for 2025"> <div class="newsletter__post-text"> <h3>Kotlin Multiplatform development roadmap for 2025</h3> <p>2025 is set to take Kotlin Multiplatform to new heights! With key goals like making Compose Multiplatform for iOS stable, releasing the first public version of direct Kotlin-to-Swift export, and launching a standalone KMP IDE based on JetBrains Fleet, the future is looking brighter than ever. I can’t wait to join you on this journey! 🌟</p> <a href="https://blog.jetbrains.com/kotlin/2024/10/kotlin-multiplatform-development-roadmap-for-2025/" class="btn" target="_blank">Check out the roadmap</a> </div> </article> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/amp-social_share_blog_1280x720_en.png" alt="Amper Update November 2024 – Project File Tooling, Compose Resources, KSP2, and Android Release Builds"> <div class="newsletter__post-text"> <h3>Amper update November 2024</h3> <p>Amper 0.5.0 is loaded with some excellent updates! New in-IDE warnings and quick-fixes for working with multiple modules, improved nested completion, and support for Compose Multiplatform resources make it easier to build multiplatform projects. Plus, Amper now supports KSP2, creates signed release builds of Android apps, and enables you to turn on the Parcelize plugin for Android. I hope you’re as excited as I am about these new features! Don’t forget to try them out and let me know how it goes – your feedback will help shape the future of Amper. 🙌</p> <a href="https://blog.jetbrains.com/amper/2024/11/amper-update-november-2024/" class="btn" target="_blank">Learn more about the update </a> </div> </article> </div> <div class="newsletter"> <h2>Other news</h2> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Gradle2.png" alt="Declarative Gradle EAP 2 is live"> <div class="newsletter__post-text"> <h3>Declarative Gradle EAP 2 is live</h3> <p>My dear friend Gradlephant shared some great insights with me – the second Early Access Preview of Declarative Gradle has been released! Take a look at some of this EAP’s highlights:<br /> – Official Android Gradle plugin integration preview.<br /> – The ability to configure software types from Kotlin DSL build definitions.<br /> – New DCL language features: enum properties and conditional containers.<br /> – Language Server for Declarative Gradle.</p> <a href="https://blog.gradle.org/declarative-gradle-november-2024-update" class="btn" target="_blank" rel="noopener">Read on for more details</a> </div> </article> <article class="newsletter__post"> <img decoding="async" class="newsletter__post-img" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Advent-of-Code.jpg" alt="Advent of Code in Kotlin 2024"> <div class="newsletter__post-text"> <h3>🎄 Advent of Code in Kotlin</h3> <p>Ho-ho-hold on to your code! <a href="https://www.youtube.com/watch?v=r7nMRJ57QA0" target="_blank" rel="noopener">Advent of Code 2024</a> is almost here, so get ready to sleigh some coding puzzles with Kotlin. Start gearing up for 25 days of merry challenges, livestreams, prizes, and community cheer. Who knows, maybe I’ll even pop by with some coding tips! Are you ready? Let’s get festive! </p> <a href="https://blog.jetbrains.com/kotlin/2024/11/advent-of-code-2024-in-kotlin/" class="btn" target="_blank">Sleigh the challenges</a> </div> </article> </div> ]]></content:encoded> </item> <item> <title>Solve Advent of Code 2024 Puzzles in Kotlin and Win Prizes</title> <link>https://blog.jetbrains.com/kotlin/2024/11/advent-of-code-2024-in-kotlin/</link> <dc:creator><![CDATA[Ksenia Shneyveys]]></dc:creator> <pubDate>Mon, 25 Nov 2024 20:05:33 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/Featured_1280x720-2x.png</featuredImage> <category><![CDATA[news]]></category> <category><![CDATA[advent-of-code]]></category> <category><![CDATA[events]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=kotlin&p=529945</guid> <description><![CDATA[TL;DRAdvent of Code is the perfect opportunity to level up your Kotlin skills, whether you are a beginner or looking to finally tackle that advanced Kotlin feature you’ve been curious about. Here’s what’s in store: So join in, solve some Advent of Code puzzles, and enjoy the holiday coding spirit with Kotlin! About Advent of […]]]></description> <content:encoded><![CDATA[ <p>TL;DR<br>Advent of Code is the perfect opportunity to level up your Kotlin skills, whether you are a beginner or looking to finally tackle that advanced Kotlin feature you’ve been curious about. Here’s what’s in store:</p> <ul> <li>For the first 12 days, join daily livestreams with Sebastian Aigner, Kotlin Developer Advocate, and awesome expert guests who’ll be discussing solutions and providing real-time guidance and insights. </li> <li>You’ll also have the support of our amazing community in Slack, where everyone shares tips, ideas, and solutions – learning together makes it all the more fun.</li> <li>There are exclusive prizes to be won along the way.</li> </ul> <p>So join in, solve some Advent of Code puzzles, and enjoy the holiday coding spirit with Kotlin!</p> <figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper"> <iframe title="Advent of Code 2024 in Kotlin. Day 1." width="500" height="281" src="https://www.youtube.com/embed/r7nMRJ57QA0?list=PLlFc5cFwUnmwHaD3-qeoLHnho_PY2g9JX" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div></figure> <h2 class="wp-block-heading">About Advent of Code in Kotlin</h2> <p>Get ready to cozy up and code. JetBrains is thrilled to join Advent of Code for the fifth time, and our fourth as a sponsor. Advent of Code is an Advent calendar for everyone who enjoys programming – 25 daily, winter-themed algorithmic puzzles from December 1 to 25. The difficulty level ramps up gradually as you go through the puzzles, making this the perfect setting for both learning and fun.</p> <p>Kotlin, with its readable yet powerful syntax, is an ideal language for Advent of Code. Whether you’re new to Kotlin or a pro, Advent of Code is a great way to dive into Kotlin’s features, sharpen your problem-solving skills, and connect with a warm, enthusiastic coding community.</p> <p>Join us at <a href="https://adventofcode.com/2024" target="_blank" rel="noreferrer noopener">adventofcode.com</a> for 25 days of exciting coding puzzles – we invite you to tackle them in Kotlin.</p> <h2 class="wp-block-heading">Tune into Daily Livestreams</h2> <p>Every day at 5:00 pm UTC, Sebastian Aigner, Kotlin Developer Advocate, and special guests will go live on YouTube to walk through the daily puzzle and chat about solutions and strategies. Whether you’ve solved the puzzle or could use a hint, join us for an interactive breakdown with some festive flair.</p> <p align="center"><a class="ek-link jb-download-button" title="Join Live" href="https://www.youtube.com/playlist?list=PLlFc5cFwUnmwHaD3-qeoLHnho_PY2g9JX" target="_blank" rel="noopener">Join Live</a></p> <h2 class="wp-block-heading">Connect with the Advent of Code Community</h2> <p>The Advent of Code channel in Kotlinlang Slack is a fun place to hang out during the event. Every day, we’ll open a fresh thread for puzzle solutions and tips. Our most active and creative community members will be in the running for cool Kotlin prizes.</p> <p align="center"><a class="ek-link jb-download-button" title="Join Our Slack" href="https://slack-chats.kotlinlang.org/c/advent-of-code" target="_blank" rel="noopener">Join Our Slack</a></p> <h2 class="wp-block-heading">Climb the Leaderboards</h2> <p>Challenge yourself on the official Kotlin leaderboards. We’ll award exclusive prizes for top scorers and a few randomly selected participants who share their solutions on GitHub with the <code>aoc-2024-in-kotlin</code> topic. To join, head to the Leaderboard section of your Advent of Code profile and enter one of the codes below. Please join only one leaderboard so that there’s room for everyone.</p> <p>Here are the leaderboard codes for 2024:</p> <p>Leaderboard 1: 2553782-cea910db<br>Leaderboard 2: 3240094-7c19b5c5<br>Leaderboard 3: 2553918-9a53059b<br>Leaderboard 4: 2649199-76907702<br>Leaderboard 5: 2343137-3ba37431<br>Leaderboard 6: 2076885-390cf855<br>Leaderboard 7: 2716400-267b06fb</p> <h2 class="wp-block-heading">Resources</h2> <ul> <li>Kotlin <a href="https://github.com/kotlin-hands-on/advent-of-code-kotlin-template" target="_blank" rel="noopener">GitHub Template</a> for Advent of Code</li> <li>Amper <a href="https://github.com/kotlin-hands-on/advent-of-code-kotlin-template-amper/" target="_blank" rel="noopener">GitHub Template</a> for Advent of Code</li> <li><a href="https://kotlinlang.org/docs/advent-of-code.html" target="_blank" rel="noopener">Solutions</a> to Advent of Code puzzles from previous years, in idiomatic Kotlin</li> <li><a href="https://blog.jetbrains.com/kotlin/2021/12/tips-and-tricks-for-solving-advent-of-code/">Tips and Tricks for Solving Advent of Code</a></li> <li>The “<a href="https://plugins.jetbrains.com/plugin/22214-algorithmic-challenges-in-kotlin" target="_blank" rel="noopener">Algorithmic Challenges in Kotlin</a>” course</li> </ul> <h2 class="wp-block-heading">Template</h2> <p>Use our GitHub template to set up your Advent of Code Kotlin project instantly. This template streamlines your setup, automatically removes unnecessary files, and customizes your project with your username and name.</p> <p>To start, log in to GitHub, click “Use this template” (don’t fork!), and clone it in IntelliJ IDEA once setup is complete.</p> <figure class="wp-block-image size-full is-resized is-style-default"><img decoding="async" fetchpriority="high" width="2506" height="1006" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Advent-of-Code-template.png" alt="Advent of Code in Kotlin template" class="wp-image-529973" style="aspect-ratio:2.4910536779324057;width:840px;height:auto"/></figure> <p>If our Advent of Code template helped you with Advent of Code, give it a star!</p> <h2 class="wp-block-heading">How to Win Prizes</h2> <p>Want to win exclusive Kotlin prizes? Follow these steps:</p> <ol> <li>Complete at least three Advent of Code 2024 puzzles using Kotlin.</li> <li>Share your solutions on GitHub, adding the topic <code>aoc-2024-in-kotlin</code>.</li> <li>Make sure we can contact you through your GitHub profile (email address or X handle).</li> <li>When competing for top scores, honor the Advent of Code guidelines, which forbid you from using AI or LLMs to solve the puzzles.</li> </ol> <p>To add the <code>aoc-2024-in-kotlin</code> topic in your repository, edit the repository details by clicking the gear icon in the top right-hand corner of the repository page. Next, in the topics field, add the value <code>aoc-2024-in-kotlin</code>:</p> <figure class="wp-block-image size-full"><img decoding="async" width="1292" height="1002" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Advent-of-Code-in-Kotlin-topic.png" alt="Advent of Code in Kotlin 2024" class="wp-image-529984"/></figure> <p>Happy coding – see you there! </p> ]]></content:encoded> </item> <item> <title>JetBrains AI Assistant Integrates Google Gemini and Local LLMs</title> <link>https://blog.jetbrains.com/ai/2024/11/jetbrains-ai-assistant-integrates-google-gemini-and-local-llms/</link> <dc:creator><![CDATA[Irina Mariasova]]></dc:creator> <pubDate>Fri, 22 Nov 2024 14:55:23 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/jbai-featured_blog_1280x720_en-2.png</featuredImage> <category><![CDATA[news]]></category> <category><![CDATA[gemini]]></category> <category><![CDATA[google]]></category> <category><![CDATA[jetbrains-ai]]></category> <category><![CDATA[mellum]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=ai&p=529591</guid> <description><![CDATA[We’ve now added Gemini 1.5 Pro and Gemini 1.5 Flash to the lineup of LLMs used by JetBrains AI Assistant. These LLMs join forces with OpenAI models and local models. What’s special about Google models? Gemini 1.5 Pro and 1.5 Flash on Google Cloud’s Vertex AI will deliver advanced reasoning and impressive performance, unlocking several […]]]></description> <content:encoded><![CDATA[ <p>We’ve now added Gemini 1.5 Pro and Gemini 1.5 Flash to the lineup of LLMs used by JetBrains AI Assistant. These LLMs join forces with OpenAI models and local models. </p> <h2 class="wp-block-heading">What’s special about Google models?</h2> <p>Gemini 1.5 Pro and 1.5 Flash on Google Cloud’s Vertex AI will deliver advanced reasoning and impressive performance, unlocking several new use cases. Gemini Flash 1.5 will specifically help when cost efficiency at high volume and low latency is paramount. </p> <h2 class="wp-block-heading">How to try Google models</h2> <p>Starting from the <a href="https://blog.jetbrains.com/ai/2024/11/jetbrains-ai-assistant-2024-3/">2024.3 version of JetBrains AI Assistant</a>, you can pick your preferred LLM right in the AI chat. This expanded selection allows you to customize the AI chat’s responses to your specific workflow, offering a more adaptable and personalized experience. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeEjL15eYljlJlQQCzWvFNcjlatWbEqVMkp6mcEE-amMnF8vDR04JYcSKqNGPAqb9n60pxaZZx-XZwF5tE3Vny4FHvN7l6AB7YOhavKxsqGIX6OrEYrqaMVXlVX-P8gVKGlVbdPtA?key=l9CleK8rUDp4xnOhCF3QZqG8" alt=""/></figure> <h2 class="wp-block-heading">Local model support via Ollama</h2> <p>In addition to cloud-based models, you can now connect the AI chat to local models available through <a href="https://ollama.com/" target="_blank" rel="noopener">Ollama</a>. This is particularly useful if you need more control over your AI models, and it offers enhanced privacy, flexibility, and the ability to run models on local hardware.</p> <p>To add an Ollama model to the chat, enable Ollama support in AI Assistant’s settings and configure the connection to your Ollama instance. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfxECpyxl41SzCCjh_uFUtPgxIC0ggx2c0KTKpviyVaMhJuTmweBmDQJKTfLdaqbMIuqLm1kfzuekhcR-ZYPgwDeXWsdt8r6ixs9MD0TFddecEPaF--k6wXIW1aIGxGKK_0-dajxQ?key=l9CleK8rUDp4xnOhCF3QZqG8" alt=""/></figure> <p>Explore these new models, and let us know what you think! 🌟</p> ]]></content:encoded> </item> <item> <title>CLion Nova Improvements, Debug Servers, OpenCV Image Viewer, and Zephyr West Debugging in CLion 2024.3</title> <link>https://blog.jetbrains.com/clion/2024/11/2024-3-available/</link> <dc:creator><![CDATA[Oleg Zinovyev]]></dc:creator> <pubDate>Wed, 20 Nov 2024 11:40:48 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/Featured_Blog_1280x720-2x-8.png</featuredImage> <category><![CDATA[news]]></category> <category><![CDATA[releases]]></category> <category><![CDATA[ai-assistant]]></category> <category><![CDATA[clionnova]]></category> <category><![CDATA[debugger]]></category> <category><![CDATA[embedded]]></category> <category><![CDATA[misra]]></category> <category><![CDATA[opencv]]></category> <category><![CDATA[zephyr-west]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=clion&p=527231</guid> <description><![CDATA[CLion 2024.3 is now available. This latest version of the JetBrains IDE for C and C++ includes the following key features and updates: You can download CLion 2024.3 from the link below, via the Toolbox App, as a snap package if you’re using Ubuntu, or via a patch update from version 2024.2. DOWNLOAD CLION 2024.3 […]]]></description> <content:encoded><![CDATA[ <p>CLion 2024.3 is now available. This latest version of the JetBrains IDE for C and C++ includes the following key features and updates:</p> <ul> <li>Considerable improvements to the new language engine, CLion Nova.</li> <li>New <em>Debug Servers</em> configuration option.</li> <li>OpenCV image viewer.</li> <li>Ability to attach the debugger to an unstarted process.</li> <li>Debugging support for Zephyr West.</li> </ul> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1600" height="900" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/image-36.png" alt="CLion 2024.3" class="wp-image-528602"/></figure> <p>You can download CLion 2024.3 from the link below, via the <a href="https://www.jetbrains.com/toolbox-app/" target="_blank" rel="noopener">Toolbox App</a>, as a snap package if you’re using Ubuntu, or via a patch update from version 2024.2.</p> <p align="center"><a class="jb-download-button" href="https://www.jetbrains.com/clion/download/" target="_blank" rel="noopener" data-test="blog-article-cta"><i class="download-icon"></i>DOWNLOAD CLION 2024.3</a></p> <h2 class="wp-block-heading">CLion Nova</h2> <p>In this release, our new language engine, CLion Nova, has received many important enhancements, including various language-specific and UI updates and several memory usage optimizations. We’ve also provided improved language support for modern C++ features.</p> <p>Furthermore, to simplify the transition from CLion Classic to CLion Nova, we’ve added a toggle switch to both the <em>Welcome</em> screen and the <em>Configuration</em> menu.</p> <figure class="wp-block-image size-full is-resized"><img decoding="async" loading="lazy" width="1172" height="564" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/1_nova_feedback.png" alt="CLion Nova toggle switch" class="wp-image-528734" style="aspect-ratio:2.078014184397163;width:645px;height:auto"/></figure> <h3 class="wp-block-heading">Call for feedback on CLion Nova</h3> <p>The performance of CLion Nova now exceeds that of CLion Classic by an even greater margin. It’s smoother and more responsive, even on larger projects with hundreds of thousands of lines of code. That’s why we’ve added even more convenient ways for you to switch to CLion Nova. </p> <p>However, we realize that some CLion Classic users are not ready to make the switch. Before we make CLion Nova the default engine for everyone, we would like to understand why some users prefer CLion Classic over CLion Nova. We would therefore appreciate it if you could share your feedback with us via <em>Help</em> | <em>Submit Feedback…</em> in the main IDE menu. We’ll review it carefully and try to resolve any critical issues that might prevent you from getting the most out of CLion Nova.</p> <h3 class="wp-block-heading">Memory usage improvements</h3> <p>Various improvements have vastly reduced CLion Nova’s memory usage and improved overall IDE performance. This is especially noticeable in large projects like <a href="https://www.chromium.org/chromium-projects/" target="_blank" rel="noopener">Chromium</a> ones.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1790" height="1104" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/2_nova_memory.png" alt="Chromium project memory usage" class="wp-image-528745"/></figure> <p>For example, when we compared the memory usage of a Chromium project in CLion Nova 2024.2 with the same project in 2024.3, we saw that the IDE frontend used 51% less memory in the new version, and the IDE backend used 15% less. In short, this means the IDE has become more responsive and quicker to launch.</p> <h3 class="wp-block-heading">Call hierarchy</h3> <p>The function call hierarchy is now available when using CLion Nova in the <em>Hierarchy</em> tool window. It displays caller and callee hierarchies, visually representing how your functions interact and highlighting recursive calls with the corresponding icon.</p> <figure class="wp-block-image size-full"><img decoding="async" data-gif-src="https://blog.jetbrains.com/wp-content/uploads/2024/11/3_call_hierarchy-1.gif" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/3_call_hierarchy.png" alt="Quick definition" width="800" class="wp-image-528296"/></figure> <p>To see the call hierarchy of a function, select it in the editor, and then click <em>Navigate</em> | <em>Call Hierarchy</em> from the main menu or use the shortcut <em>⌃⌥H</em> (macOS) or <em>Ctrl+Alt+H</em> (Windows/Linux).</p> <h3 class="wp-block-heading">Predefined code styles from other projects</h3> <p>One of the most requested features we’ve added to this release is predefined code styles from other projects such as LLVM, GNU, Qt, and Google. This allows you to follow popular style guides for code structure rules, naming conventions, and other C++ areas where consistency is crucial. You can select your preferred style via <em>Settings</em> | <em>Editor</em> | <em>Code Style</em> | <em>C/C++</em> | <em>Set from…</em>.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="2696" height="1616" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/4_code_styles.png" alt="Predefined code styles" class="wp-image-528756"/></figure> <h3 class="wp-block-heading"><em>Quick Definition</em> support</h3> <p>The <em>Quick</em> <em>Definition</em> popup reveals where and how function, class, method, and other project symbols are defined. To call it, place the caret at a symbol in the editor and press <em>⌥Space</em> (macOS) or <em>Ctrl+Shift+|</em> (Windows/Linux). You can also access it from the main menu via <em>View</em> | <em>Quick Definition</em>.</p> <figure class="wp-block-image size-full"><img decoding="async" data-gif-src="https://blog.jetbrains.com/wp-content/uploads/2024/11/6_quick_definition.gif" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/6_quick_definition.png" alt="Quick definition" width="800" class="wp-image-528329"/></figure> <h2 class="wp-block-heading">Embedded development</h2> <p>In this release, we have continued to expand CLion’s functionality to meet the diverse needs of embedded developers. Major updates for embedded development include debug servers, the ability to edit peripheral register values, and support for debugging West projects.</p> <h3 class="wp-block-heading">Debug servers <strong><sup><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">experimental</mark></sup></strong></h3> <p>We’ve introduced a new <em>Debug Servers</em> configuration option to simplify the setup of debugging for embedded and remote development. Located in <em>Settings</em> | <em>Debugger</em>, this dedicated section allows you to configure a debug server for the specific debug probe and use it to run or debug the build target.</p> <p>To enable the configuration option, go to <em>Settings</em> | <em>Advanced Settings</em> | <em>Debugger</em>. You can select <em>Edit Debug Servers</em> from the main toolbar switcher or go to <em>Settings</em> | <em>Debugger </em>and open the <em>Debug Servers</em> dialog to configure a debug server.</p> <figure class="wp-block-image size-full"><img decoding="async" data-gif-src="https://blog.jetbrains.com/wp-content/uploads/2024/11/7_debug_servers.gif" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/7_debug_servers.png" alt="Debug servers" width="800" class="wp-image-528373"/></figure> <p>Please be aware that this is an experimental feature, and it doesn’t work with PlatformIO yet. There is, however, a <a href="https://youtrack.jetbrains.com/issue/CPP-42014/Debug-Servers-are-not-compatible-with-PlatformIO" target="_blank" rel="noopener">workaround</a>. We encourage you to give it a try and share your feedback with us. Additionally, we are more than willing to arrange a <a href="https://survey.alchemer.com/s3/8011393/CLion-EAP-Feedback" target="_blank" rel="noopener">brief call</a> to understand your specific use cases and challenges better.</p> <h3 class="wp-block-heading">Debugging support for Zephyr West</h3> <p>Now, you can natively debug Zephyr projects that use the West meta-tool <a href="https://www.jetbrains.com/help/clion/2024.2/zephyr.html#run-debug-configuration" target="_blank" rel="noopener">directly in CLion</a>. When you import your Zephyr West project, a West run/debug configuration is automatically created in the <em>Run/Debug Configurations</em> switcher. You can also create a new run/debug configuration by selecting <em>Run</em> | <em>Edit Configurations…</em> from the main menu, clicking <em>+</em>, and selecting a <em>West</em> template:</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1982" height="1066" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/8_west_debug.png" alt="Zephyr West debug configuration" class="wp-image-528767"/></figure> <p>Once configured, the new West run/debug configuration will be available in the <em>Run/Debug Configurations</em> switcher, and you can use it to run a debug session.</p> <h3 class="wp-block-heading">Editable peripheral register values</h3> <p>When debugging board peripherals like timers, communication interfaces, or GPIO ports, you can now instantly observe the results of your modifications by editing peripheral registers directly in the <em>Peripherals</em> pane.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1823" height="689" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/9_peripherals.png" alt="Editable peripheral register values" class="wp-image-528778"/></figure> <p>You can test different configurations and device states on the go without recompiling your code or reloading your application or board.</p> <h3 class="wp-block-heading">Support for MISRA C++:2023 with CLion Nova</h3> <p>The <a href="https://misra.org.uk/" target="_blank" rel="noopener">MISRA guidelines</a> are indispensable in the development of safety-critical systems. In this release, CLion’s static analysis toolset gets a <a href="https://youtrack.jetbrains.com/articles/CPP-A-191430682/MISRA-checks-supported-in-CLion#misra-c-2023-67-177" target="_blank" rel="noopener">significant portion</a> of MISRA C++:2023 checks specifically targeted at C++17.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="2340" height="1222" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/10_misra.png" alt="MISRA C++:2023 checks" class="wp-image-528789"/></figure> <h2 class="wp-block-heading">Debugger</h2> <p>CLion’s debugger has received several updates, the most important of which are an OpenCV image viewer, the ability to attach the debugger to an unstarted process, a formatted view for strings with structured data, and new bundled GDB (15.2) and LLDB (19.1.3) debuggers.</p> <h3 class="wp-block-heading">OpenCV image viewer</h3> <p>If you’re developing an ML application that uses the OpenCV library, you can now view a two-dimensional OpenCV array as an image while debugging the application. The image opens in a separate dialog with multiple editing options.</p> <figure class="wp-block-image size-full"><img decoding="async" data-gif-src="https://blog.jetbrains.com/wp-content/uploads/2024/11/11_opencv_viewer.gif" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/11_opencv_viewer.png" alt="OpenVC image viewer" width="800" class="wp-image-528420"/></figure> <p>The OpenCV image viewer simplifies image processing inspection during application debugging. It’s also more convenient than alternative methods like saving an image to the hard drive or writing extra code to display it in a popup window.</p> <h3 class="wp-block-heading">Ability to attach the debugger to an unstarted process</h3> <p>Attaching the debugger to an unstarted local process is helpful when one part of your project is written in C++ and runs in CLion, while another is written in another language and runs in an external environment.</p> <p>To try the feature:</p> <ul> <li>Set a breakpoint in your code.</li> <li>Select <em>Run</em> | <em>Attach to an Unstarted Process…</em> from the main menu.</li> <li>In the <em>Command line </em>field, add a pattern to find the process using wildcard characters: <code>*process_name*</code>.</li> <li>Select the options you need.</li> <li>Select a debugger to attach.</li> <li>The debugger will start watching the process.</li> </ul> <p></p> <figure class="wp-block-image size-full"><img decoding="async" data-gif-src="https://blog.jetbrains.com/wp-content/uploads/2024/11/13_debug_unstarted_process.gif" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/13_debug_unstarted_process.png" alt="Attaching the debugger to an unstarted process" width="800" class="wp-image-528457"/></figure> <p>Once the external process starts, the debugger will attach to it. From there, the debugging session will continue as normal, with the program running and halting at the breakpoints you have set.</p> <h3 class="wp-block-heading">Formatted view for strings with JSON, XML, or HTML data</h3> <p>When debugging strings containing JSON, XML, or HTML data, or newline characters, you can view them formatted according to their code style directly in the debugger. This means you no longer need to copy unformatted values into a third-party tool for examination. </p> <p>When debugging, click <em>View</em> next to a variable to see the structured or raw data in a separate window.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="2236" height="1095" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/12_formatted_strings_view.png" alt="Formatted view for strings with JSON, XML, or HTML" class="wp-image-528800"/></figure> <h2 class="wp-block-heading">Other enhancements</h2> <p>This release also includes a number of user experience improvements, such as renewed cloud completion, a new project status widget, and an updated UI for the new terminal. We’ve also updated the CMake bundle to 3.30.5.</p> <h3 class="wp-block-heading">Renewed cloud completion powered by AI Assistant </h3> <p>The enhanced JetBrains AI Assistant plugin, featuring our internally trained LLM for C++, has significantly improved the speed and intelligence of CLion’s cloud code completion. AI Assistant now provides more usage scenarios, better suffix matching, and more correct code fragment completions.</p> <p>One of the most significant enhancements is multiline code completion, which brings syntax highlighting and the ability to incrementally accept code suggestions. </p> <figure class="wp-block-image size-full"><img decoding="async" data-gif-src="https://blog.jetbrains.com/wp-content/uploads/2024/11/14_ai_assistant.gif" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/14_ai_assistant.png" alt="Renewed cloud completion" width="800" class="wp-image-528476"/></figure> <p>Multiline code completion operates alongside standard code completion and Full Line Code Completion (the latter uses the local LLM and doesn’t require sending data to the cloud). It allows you to review and accept suggestions incrementally. Additionally, you can accept suggestions word by word using the shortcut <em>⌥→</em> on macOS or <em>Ctrl+→</em> on Windows. </p> <h3 class="wp-block-heading">Project status widget</h3> <p>CLion’s project status notifications inform you of potential problems with your project configuration and offer ways to resolve them. In the previous CLion version, 2024.2, these notifications were displayed as yellow banners in the editor until the problem was resolved. They were irrelevant for some users – for example, those who just wanted to open a .cpp file from a third-party project to read the code. Having a notification banner hanging in the editor all the time is unnecessary in such cases.</p> <p>For this release, we’ve moved project status notifications from the top of the editor to a new widget in the status bar.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="2760" height="1608" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/16_status_widget.png" alt="Project status widget" class="wp-image-528811"/></figure> <p>Now, the notification that your file doesn’t belong to any project won’t appear until you hover over the ⚠️ icon. When you click on the icon, the widget will offer to fix the problem. This makes notifications less distracting while still keeping the information accessible to those who want it.</p> <h3 class="wp-block-heading">Updated UI for the new terminal</h3> <p>The new terminal’s interface has been redesigned to be more compact by reducing padding. This change maximizes screen space, making it easier to view and work with commands while keeping everything readable and clear. </p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="2804" height="1248" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/17_new_terminal.png" alt="Updated UI for the new terminal" class="wp-image-528822"/></figure> <h3 class="wp-block-heading">Highlighted occurrences of selected text</h3> <p>By default, CLion now highlights every instance of the text you select in any file type, not just .c and .cpp files. This change makes it much simpler to track where your selected text appears throughout the file. </p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="2026" height="954" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/18_highlighting_occurrences.png" alt="Highlighted occurrences of selected text" class="wp-image-528833"/></figure> <h2 class="wp-block-heading">Try CLion and give us your feedback</h2> <p>We invite you to give CLion 2024.3 a try. If you have an active subscription, you can update it right away. New to CLion? Start your free 30-day trial today and dive into all its features and improvements immediately.</p> <p>We value your feedback! If you have anything to share or if you run into any problems, please let us know through our issue <a href="https://youtrack.jetbrains.com/issues/CPP" target="_blank" rel="noopener">tracker</a>.</p> <p align="center"><a class="jb-download-button" href="https://www.jetbrains.com/clion/download/" target="_blank" rel="noopener" data-test="blog-article-cta"><i class="download-icon"></i>DOWNLOAD CLION 2024.3</a></p> <p>Your CLion team<br> <em>JetBrains</em><br> <em>The Drive to Develop</em></p> ]]></content:encoded> </item> <item> <title>Deploying Go Apps with Kubernetes</title> <link>https://blog.jetbrains.com/go/2024/11/20/deploying-go-apps-with-kubernetes/</link> <dc:creator><![CDATA[Mukul Mantosh]]></dc:creator> <pubDate>Wed, 20 Nov 2024 11:24:31 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/go-featured_blog_1280x720_en-1.png</featuredImage> <category><![CDATA[tutorials]]></category> <category><![CDATA[go]]></category> <category><![CDATA[goland]]></category> <category><![CDATA[kubernetes]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=go&p=528858</guid> <description><![CDATA[We live in a world where things change at a rapid pace, and the latest and greatest quickly becomes outdated. The same goes for deploying applications to servers. You used to have to physically travel to a data center to deploy your changes. Later on, we moved to VMs. Then containers came along and changed […]]]></description> <content:encoded><![CDATA[ <p>We live in a world where things change at a rapid pace, and the latest and greatest quickly becomes outdated. The same goes for deploying applications to servers. You used to have to physically travel to a data center to deploy your changes. Later on, we moved to VMs. Then containers came along and changed the game again.</p> <p>Containers have been widely adopted by most industries, and one of the most popular containerization tools is <a href="https://www.docker.com/" target="_blank" rel="noopener">Docker</a>. However, as complexity grew, people started looking for orchestration tools that were effective at scale, performed load balancing, self-healed, and more. There were many contenders in the competition, like <a href="https://mesos.apache.org/" target="_blank" rel="noopener">Apache Mesos</a>, <a href="https://www.nomadproject.io/" target="_blank" rel="noopener">HashiCorp Nomad</a>, and <a href="https://docs.docker.com/engine/swarm/" target="_blank" rel="noopener">Docker Swarm</a>, but Kubernetes has thrived for a long time due to its robust ecosystem, extensive community support, scalability, and ability to manage complex, distributed applications across multiple environments.</p> <figure class="wp-block-image aligncenter size-full is-resized is-style-default"><img decoding="async" loading="lazy" width="894" height="894" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Artboard-1-2x.png" alt="" class="wp-image-529509" style="width:50%;height:auto;margin-left:auto;margin-right:auto;display:block"/></figure> <p style="font-size:12px;">Source: <em>drgarcia1986.medium.com</em></p> <p><a href="https://kubernetes.io/" target="_blank" rel="noopener">Kubernetes</a> is an open-source container orchestration platform that automates the deployment, scaling, and management of containerized applications. Originally developed by Google, it is now maintained by the <a href="https://www.cncf.io/projects/" target="_blank" rel="noopener">CNCF</a>.</p> <p>Kubernetes is one of the largest open-source projects to date. With over a decade of development, its maturity is undeniable, boasting more than 88,000 contributors. Check out the <a href="https://kubernetes.io/blog/2024/06/06/10-years-of-kubernetes/" target="_blank" rel="noopener">10 Years of Kubernetes</a> blog post for more insights.</p> <p>In this tutorial, we are going to create a Go application and prepare it to run inside a Kubernetes cluster. </p> <p>Let’s get started!</p> <h1 class="wp-block-heading">Creating a Go application in GoLand</h1> <p>In this tutorial, we’ll start by creating a basic Go application which performs CRUD operations. We’ll then containerize the application and deploy it to the local Kubernetes cluster using Docker Desktop.</p> <p>You can access the source code used in this tutorial <a href="https://github.com/mukulmantosh/go_kubernetes" target="_blank" rel="noopener">here</a>.</p> <p>To create your project, launch GoLand and click <em>New Project</em>. </p> <p>Provide necessary information such as the project name, <a href="https://www.jetbrains.com/help/go/configuring-goroot-and-gopath.html#goroot" target="_blank" rel="noopener">GOROOT</a>, and environment variables.</p> <p>Even if you don’t have the Go SDK installed on your system, GoLand will assist you in <a href="https://www.jetbrains.com/help/go/configuring-goroot-and-gopath.html#download-go-sdk" target="_blank" rel="noopener">downloading</a> the correct SDK.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcMKDzdcC-JvIzy398LQmTt3Zbs7Ji6XxQpUPCOoBSU80oZKW15QcNFnJ7h0PN7UZdR7IHQzIm7mRCL-fYZ03P2uZr9P3MZiY99ukm4HZhUBBtwEZMVxItjtor6tX0YAKn-f-RYpS4RNeDkp54ACHUu_PI?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Then click <em>Create</em>.</p> <h2 class="wp-block-heading">Installing packages</h2> <p><strong>Gorilla Mux</strong></p> <p>Once the project has been created, install <a href="https://gorilla.github.io/" target="_blank" rel="noopener">Gorilla</a>. The Gorilla Mux package is among the most widely used routers. It offers functionalities for route matching, serving static files, supporting middleware and websockets, managing CORS requests, and testing handlers.</p> <p>Installing it from GoLand is simple and straightforward. Just import the package name, and the IDE will prompt you to install it.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcptza6O49QG_SMXQdAWGYstxGMMb4qwEExlChEE-4WyZ7V8rKqVEGKootXpdJX-Dbwg0UW0hbt3dr3Ey8AELPFIzm5kbxgTatdEgFQTzuWj4lqMSDgI6uMfmltQg-46XzeYlIAdnT_HlKiTkCJnto2MUvp?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Alternatively, you can use the default method by accessing the Terminal and executing the following command:</p> <pre class="EnlighterJSRAW">go get -u github.com/gorilla/mux</pre> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcFRW7G6ocK6eSSCBtySfoMejCA-lMySSIFCQdTy0O1iERTTrWry_wwDhkSM0arUyliw46Q9komZQDyOROdLldXqVMocWcpwitVZywplmOvt226a60zgkw8hz3odJzf1qyuHfwjCQa51-D15w8iTE3RPn3j?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p><strong>GORM</strong></p> <p><a href="https://gorm.io/" target="_blank" rel="noopener">GORM</a> is an Object Relational Mapping (ORM) library for Go. It simplifies database interactions by making it easier for developers to work with database records and perform CRUD (Create, Read, Update, Delete) operations.</p> <p>*<strong>NOTE</strong>: We will be using the <a href="https://www.postgresql.org/" target="_blank" rel="noopener">Postgres</a> driver.</p> <p>To install, run the following command in the Terminal:</p> <pre class="EnlighterJSRAW">go get -u gorm.io/gorm go get -u gorm.io/driver/postgres</pre> <p>Alternatively, you can also directly mention the package in the <a href="https://go.dev/doc/modules/gomod-ref" target="_blank" rel="noopener">go.mod</a> file and GoLand will take care of the installation.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXceZEY0Wc48Koyq2r4wd2RZ-dxp-rp9juOeDidnteZNAy6ppjty4hUVFdDEmvMwW3odUyYOd69FfFC8hbEIzFMRlOGxTSx-VoNNDXJvIJwwQwE3c0PTRBWwdUyH4fYwYZqGFjfJ_bHugjI9KLECw0VBuGt0?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcoXq-a4276ZlhdyHVFMtigUK1Ol2vZvwXB34xUHFd97PcHy02Ecl8gBshUTq7tAPHAK8A8_CQ0ywLVIJ-SdCC8sHiL49phkKD3Z70WqzrtmVvdQ9p1kcPSd8bDlgyqWkh6WeEzlOlX_TJfsbm_G_4IbBdP?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p><strong>NOTE</strong>: When you see <code>// indirect</code> next to a dependency in the <code>require</code> block of your <code>go.mod</code> file, it indicates that your project does not import this package directly in its code, but some other package that your project imports does. </p> <h2 class="wp-block-heading">Building core business functions</h2> <p>Now, we have installed the core packages required to build the application. It’s time to start writing the core business logic. </p> <h3 class="wp-block-heading">Database</h3> <p>Let’s begin with the database.</p> <p>Create a <code>database.go</code> file under project root. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcoTEt8J2UMn81H7vv8n9IxIpO0bfU2ZfsNFApea6920wzWAn5GoJGFNDhy7_y_apAaeoNwOx5PUgcyAoS40Q73GRxctTm5TLLNIcm3MVs3x3myX0VuEKAdMADGpiius2UYSpXRV4qp8peEKEcY7Zo9p4ko?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Let’s break it down step-by-step. </p> <p>In this section we are managing a database client using the GORM library for Postgres.</p> <ol> <li><strong><code>DBClient</code></strong>: This is an interface with two method signatures:</li> </ol> <ul> <li><strong><code>Ready()</code></strong>: This function returns a boolean value based on whether the database is ready or not. </li> <li><strong><code>RunMigration()</code></strong>: This function performs database migrations. </li> </ul> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXc7OdvHhC7dQ90PHYLJCAiekFEYMY_Ea3XLWHBk1d-LYwNKNG6mytgtxLY0xD64z8MEZgTyY5egkqdJfsiDLsGK4mGNQGJ51Uph4jZvEiBP0bfMSskojQW3k37os1J9IINFXV6WPT1dm447xRw53b9mGRX_?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <ol start="2"> <li><strong><code>Client</code></strong>: This is a concrete type <code>Client</code> that implements the <code>DBClient</code> interface. It contains a single <code>db *gorm.DB</code> field which points to a <code>gorm.DB</code> instance.</li> </ol> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdUQvsNWGmnEhTjPSHvz2a65eQycqkpo79VoOR569qm6tawBz3hnYHTqM_iwNsdRlsJfBvuNutBHhBX6ftuYMYKPobRBgQQWmlsc0Q4ZtvU0KTj0zyO4-olgDf5Cr_olwrEceNF5AUlijfYVu6rWM7NomI1?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <ol start="3"> <li>Next, in the <code>Ready</code> method we perform a RAW SQL query to check database readiness. It will return a boolean response (true or false). </li> </ol> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfnc1CWg_OZ5dRdh8snZ-0mkhsAt5bLb91mwr9kafhKrXHWOkhDcM8YG1b9Z3cIDKXnCtlKXGaKj-AFT0AOZUF-9TAce4V7Z3TxZjPYG1WxocqYmT1WmSntAowZMAgBWPXwwPsoyOQGJhCehSYLj_hiz0Rj?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <ol start="4"> <li>Under <strong><code>RunMigration</code></strong>, we first check whether the database is ready. If successful, we proceed to invoke the <code>AutoMigrate</code> method provided by GORM to apply migrations to the database schema. As noted in the comment, we need to register the model to run the migration. We haven’t created a model yet, but don’t worry – we’ll get to that shortly. </li> </ol> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfG0UMHBTzgN8stvwllpG0Dpc2NAku1NhDHMgcot_fX1NyRCknwtbh9mAXCKbir4fTKdRWbyLPOoOhQ5KRUc7648csDIYMszYcrTpsHRCRoIdCMyl3nvi8ysuj18I5MJPQAf-8HxD1OOVROjQOh4uAtrMjs?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <ol start="5"> <li>The <code>NewDBClient</code> function constructs a database connection from environment variables, creating a <code>Client</code> that can be used to interact with the database.</li> </ol> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe80O40fDLowwWQpZLCQLJYD3XuBt3IxdFRQ_6zS3RUJ9xqDyor8pEyyuJW0XQsZPXP0wZJNKS5eRBakVuByOCrEaq324zTsuoY0f88QtuuD-nt3RFMTjkbLdooqNF0iMEhxZj-_zlYBQ8ARpe2F6BOEzph?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>The database section is done. Now let’s create our user model. </p> <h3 class="wp-block-heading">User model</h3> <p>Create a <code>model.go</code> file under the project root. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXc7hPLQP_SI5z_PhRlBRdbyV0r1lkhYDBllcnagGenY6SVvGsLE-Vx86I-DccbLCEEaZNdOTwzjAbGUZV8Ug1YpKP6VQgfz26GYMgh_EEETtnsvWlWSDtmrhEe391bqZweKp_FygvUoFgnFzx5OHe9Qz5Y?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcd5nG-228uRCWhJVeD_kPHujxCRkwGaB0OOzIdNbPakW2D5Wi6wjY6W0pHkg-1cAvsYLXIlXdkprUnt03RkG6I2ZBXKv1Df8qULibDKUR02RIKHIRiZNc5U_YCxPJ72hAR7BCaXce1B9N4yFoEIldYdupq?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Here you can see the <strong><code>User</code></strong> struct with fields <strong><code>ID</code></strong>, <strong><code>Name</code></strong>, <strong><code>Email</code></strong>, and <strong><code>Age</code></strong>, each annotated with JSON tags for serialization and GORM tags for database constraints, including primary key, uniqueness, and non-null constraints.</p> <p>These tags specify database constraints and behaviors using GORM:</p> <p><code>gorm:"primaryKey"</code>: The <code>ID</code> field is the primary key.</p> <p><code>gorm:"not null"</code>: The <code>Name</code> and <code>Email</code> fields cannot be <code>NULL</code> in the database.</p> <p><code>gorm:"unique"</code>: The <code>Email</code> must be unique across the database table.</p> <p>Now we need to pass the <code>User</code> model to the <code>AutoMigrate</code> function which we discussed earlier. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdPNWyPUyafYUMLqED0spgIg2KUztwuZSv9wnH99rfNKnWmVFHYQxQNOGHn5r11Qq-KKuo0a-GpzPwB2yxS7C58ILaWtwA51hc_KITQao17vU-s98eVq4Maf3-eQBUuO1F9YQpCpdAR5v4jXSFvi8XuNzfc?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <h3 class="wp-block-heading">Server</h3> <p>We have implemented the database and the user model, so now it’s time to construct the mux server. </p> <p>Create the <code>server.go</code> and <code>routes.go</code> files under the project root.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdteR3N0nCQhr0voNDJVbY_sXNUJPF91ANaRodDoLFARhb5QeR7PwxlqyMWoxmRc3-VnftdP3iQTKlugCyHhNB8ie5H8qEP5PfgYWv4hzltIWxLl1bp3SHFxQg8-nw_dvN4aiX0ttTZGJGCbOX618Ey8tQK?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>We’ll just leave this <code>routes.go</code> file empty for now, and we’ll cover what to do with it in the next section when we start defining HTTP handlers.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXemO_-EOIqo7ZWoIX4DDr1I4X-Gw6qO9EQ4ko6kyG-tuQGzB5uMrAFv8H9ON-qJtqLB_4BkOzy7rzwlHd-u2czRq7TgNmxwlfUMkFzALXf8y_a9EiQt-B5Y_Cnf79gwV6dKh3aZS174b7tpafPSgJK2RIxH?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Let’s break down the ‘<code>server.go</code>’ file step-by-step.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe6JXR1V-6tKokaxTOVE8k4xvZdL1dzdTVk0M9AHcE02Auj9EPqD-VN_G0Bs2AKLqIv9KVe9tM3Ln9jd19i7XFXZspoIwdMikIMpJCvXMtOX0mxKeMHLsyP-56KEgAg6pjNZRXIqN6pPdf4dif-caRmSiT5?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>The <code>Server</code> interface declares two methods: </p> <p>– <code>Start() error</code>: Starts the server and returns any errors that pop up. </p> <p>– <code>routes()</code>: Defines the server routes.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdf38_-DMxLd4pZ3BiwEpbW0ZhCw-qaf849yPHcbs3sjb1xk95LeQzf3YbrzpKyK12GSaywfy_57WbCzK3gawwXWr03_LFgrTZ0LhWZpC6Ll_wRiORRmNP0rCfDMPAZ2XDrcgPE-P_rgXiKM9SYw48NKi0K?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>The <code>MuxServer</code> struct implements the <code>Server</code> interface. </p> <p>It contains: </p> <p>– <code>gorilla *mux.Router</code>: An instance of Gorilla Mux Router. </p> <p>– <code>Client</code>: An embedded field pointing to a database client. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdZnuMqxkeVoMFfUo-76xoKkFmmKCPpD8-_NI6hq9kjVXoVz-xErk4cLK-o5Q_vUy9y9u55CNrikR0LW5yGUzkS2AsMWEs8nawD8Lj6nLgD-acrxYIlqw4md0QMeKETvKQeGQE7jDKQXvdTj0Gb0mr5bk0?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p><code>NewServer</code> is a constructor function that creates and initializes a <code>MuxServer</code> instance. </p> <ul> <li> It accepts a <code>Client</code> which refers to a database client. </li> <li> A new <code>MuxServer</code> is created with: </li> </ul> <p>– A new router from <code>mux.NewRouter()</code>. </p> <p>– The provided <code>db</code> client. </p> <p>– The <code>server.routes()</code>method is called to set up the routes. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdqy9-_o6Q-vYg-p1tHLq7TIHdPw8nl1-mIZ0aH6E-GdVH0WAhSLqRz5tUI2OVsCzgyrkvpbAZRRdNl4PknY8Ce-sJxnF8v3YJxEhFFYjvypGS8fsIZXB2-Db-9WVOm_f5sj_TwpN7si7C0hHTjSWKbyyas?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>The <code>Start</code> method takes care of starting up the HTTP server and listening on port 8080. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcUgtGDTAYtYog4GUtUAbrmKmuPfmCfr17ZDwyNA9DZc993RTB9GNpy-oe5QwjkXe-AT-rNBqMApoqNdAz3mCnIeD_6f1cb1Cdi7KoGPC5zfYTqFGNdUpGqCXajXLw13FC_FitY0QY21ast-JWJB7bvvI0?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>We haven’t defined any HTTP handlers yet, which is why the routes function is currently empty. </p> <p>Let’s take care of that now.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXd536HFvV6I24YHPgDX5nUXA72tL82awLLHyAAsbz-urdmjwkU4YokanwaxpQ-q4MM4h4SGFOEchOFC1ZeZycgIf9YABnFovAxUA3SgLlLZSWaLmwCxXDJSPwh2A4n3leE1xgKTcjvzCrZwGUNPmAwbgCI?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <h3 class="wp-block-heading">HTTP handlers</h3> <p>Create a new file called <code>controller.go</code> under the project root. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfdowRVbvWtUohs8H5757AuP8Mc_SSpf9jWlJCpvrMediNw1mVKD1W72WlvA3TjbP3Sa4fCi5Sdg5Uq_OMu_fitiBURip6TAL9X0EPJN9UlHeGRek4rkLHHEwa3edMNcbvYhijnaETMdEmfrFa5kWkKeDCZ?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Once you’ve created the file, go ahead and open <code>model.go</code> and add the following struct:</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcGKm4ZrW5JUA8a12e96CJlJ86VzuX4jjFsRs2-EjTYqY5MRkjwIPDSWjQdydsyrEne5VTp6DJQF4fj_FaRqWUcZEWk_JV64wX0vDUtb5oVLRdnvNmuiWTW0ZhQvCez3ei1s3eseosPDFO__boVYN9g1yPb?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>The <code>UserParam</code> struct serves as a data transfer object (DTO) specifically for input handling, often seen in web APIs or web forms. </p> <p><strong>Separation of Concerns:</strong></p> <p>The <code>User</code> struct represents the data structure of a user entity in the system, which corresponds directly to the database schema. The <code>UserParam</code> struct is used for handling input validation and data transfer, particularly from HTTP requests.</p> <p><strong>Security:</strong></p> <p>You’ll have better control over your data by separating fields into two categories: (1) information received from requests (like user input), and (2) information stored in the database. This gives you control over what data is exposed, enhances security by filtering out sensitive info, and ensures you only transfer necessary data between layers. </p> <p>Let’s go ahead and start implementing the HTTP handlers. </p> <p>Head back into the <code>controller.go</code> file.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfDdCsNQVI70j7PIoQ5PQE65pLb_15wCtcoFPYpJzWh-5vVOKD-5TUyT9N8osLR_DS7CsCqKKKHlISnq2n_a_8AjNwNQFfVzOlILeJOwvvvESw2ysDXuBV6EO4Nefbf7thf68xLFRiZ7QzzIK_6K3tb58w?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Let’s break it down step-by-step. We are going to implement the basic CRUD (Create, Read, Update, and Delete) operations on the <code>User</code> model. </p> <p><strong>Add User</strong></p> <p>To create a new user and add it to the database.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcLCP6Td-IHb3Ric-QT4L7IglX4_4LCl8ubXAzzsnsS2K1TxmZvuBZe2lOwzqTHFbD2omEvwct4na-bCfhMbGVjCYoN6CQAO1ZXZbOMFIfYk5w8y8RV2Mdb6xPM-947_DFYG_fnYCtf-888qr9JGkEkK-EL?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p><strong>List Users</strong></p> <p>To list all users from the database.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcYzjIcspeefaoprgTWDVFHiqVg2xn3xg8jNhxXdI6takWk1PrGH3NHd_SU-5PAIN9QxmIGtylMkiPs3iVqwrU7GYU2yI3iZ7PHRcCuKD9Y25p3cum_8XBw3wh_rj2e7jzByivcWvYtRnpR1qJzaVT65c1Q?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p><strong>Update User</strong></p> <p>To update an existing user’s details.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfzCm69OovXsvXnNtEK4O3xBkBWD_E2nc5Paq2oFq9R1lUd2qG2rgNPJ9xO24GKmdYNAJEau5NAZYwUoJ5m9OmzWWd5cgxEIstibpR_YBff6fgQVKVGuCn9X_X1O94-Ri86uBs8xjcna2cJUqFCXorbhrd8?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p><strong>Delete User</strong></p> <p>To delete an existing user.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeXXG97JVXFk2wGbOshSb04p1Wqj7jz1xHNHSlmDcKsJMoR10FFM145KtWd-c-plDKp7PQXL5nKd3fEjAmdwnYPvc_AwbHNf16FWMcJen2FCK3AtBuKx0uU_LPd9fHho6pXr3-9ZkbEqsjPnFgMoJqc6S4?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Now, it’s time to update the routes. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeCRp_XofLtNOalDVe9rULxyAs0VfusqXSvZi_V1OHk8N2PAGXamOOC7tcFDoXdeL1cZL-7nVH2cdgly4orGpOJ3llnKwZMVwGCNAvYaUcibMw7-T-xOwFtGD7cGVY7V4k8wZccIDk7rp9aWPr-zZ4AnMLt?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>In this function, we’ll set up various kinds of routes (<code>GET</code>, <code>POST</code>, <code>PUT</code> and <code>DELETE</code>) to handle requests.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdv6T4W3L5w26V9B6sTKmxT39F2jPl47Ce8hyk55p6rjekrtXBiSZ0UJV87-57rj_f8oQ4iKdZTjNlxRSpCN7SVAQfTOvpsXmOquLrvdPjiGC9xC-oCQUFRIGCKb-nSWpMKbrLQfXm9GA4MpGGmere0fPsa?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <h3 class="wp-block-heading">Running the application</h3> <p>We’re almost done! It’s time to define the entry point of the application where we can initialize the database, run migrations, and start the server.</p> <p>Create a new file called <code>main.go</code> under the project root.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfnXFGSX7lWM0kkFct5YXGox-yWXz7W09FydPakVMRxXhvpa107sAzT89wiql5nNBT7qgpcGgk_JEcQJrTgytRAcp7qgS9lLw3ESpA6tw94_li39nIIfepOFhBbRqKVAxyY2wJVJngN6A0dG6zpk95qGkw?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>As you can see from the code below, we are initializing the database client, running database migration, and starting up the server. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcoSNvOt2G9k1AVIaKxI-N_jI2HZjR-yJQbCyDcT0X-EpdzUVwEhWw_atg7MAmQz4htjD_TRuWGkcfENF5hvAYTA8mPFuuGyp8pppZqO-eOPk6PfiJYzW9yPUEX46jxAvz2cZHA8kw8v2Ac8x3lHi-t9Vsr?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Now, it’s time to start the server. Before that, make sure you are running a local instance of <a href="https://www.postgresql.org/docs/current/tutorial-install.html" target="_blank" rel="noopener">Postgres</a>. I will use Docker to spin up a postgres container.</p> <p>Run the following command in the Terminal:</p> <pre class="EnlighterJSRAW">docker run --name goland-k8s-demo -p 5432:5432 -e POSTGRES_PASSWORD=********** -d postgres</pre> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdwH9rU1eZd0E00EUp9uCVgVJ1RfI_-yz1r4R91GyP45PN-DdzqOx056D2rrme1Wsa2IOYTRffjCZ2uJ1E_45XZ2SIzdomgJ2pi8zM0pFixk6cSCAF9clUZeZe55IYSpRc5WIFp9HqqGzB4XicY2qCC7-0G?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Once the container is up and running, go ahead and modify the <a href="https://www.jetbrains.com/help/go/run-debug-configuration.html" target="_blank" rel="noopener">Run Configuration</a>. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdvzMGQ-IkAjvbKBO4qmh0txMeh8RHL5lfuRbut3Lio9oWudC31W86J2Tboeh6H6tayMVW4UgF6dNDlpn5GEf2or94NzoH9KKN3Un08T0DVoHL6wnkDn3eiDLeVMYeV4voMol0I9AElaR5xWta1AMJOq2E?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Add these variables to the <em>Environment</em> field, as shown in the image below:</p> <ul> <li>DB_HOST</li> <li>DB_USERNAME</li> <li>DB_PASSWORD</li> <li>DB_NAME</li> <li>DB_PORT</li> </ul> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdK4UZQ6WpXO_Pkx0RPjX5j0i-QbaxZdOA1qIA9A-FWU48uuAwENypjKCM8EvvhHAnaLvjfIM4M7ct0i6jxK4uk-SZqK31vNQwMKvQVXoktovk2RMk641q7qwUsTgDmxe_9s209mUmDKcT4Ow9ISmYX7DwQ?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdfLOYRRbVJl5vEv_XCbUAasuMfzYLnPLfzrDj-IBPfm9ZwUqgEY9DaM96GjvbkKkk8uv4eOWWnmIXzKCrIA1XuJujvn0St7BJ56Afnbtt_4Rm9n6vKK-CNyOnfj5WzS8V1cGg1WIHiJshdBEgt5-P05go?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Once done, apply the changes.</p> <p>Click the play icon to start the application. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeYzaMNRSqOoM8EoM-nA2m-Uvzph8Gh7uf0pzyjReZHNgj6VPfwJxSVreu4Qxvgd9QDMcYr-v8XPYcKjjak4nTciletvuFjYq6Pj31X0xHEuPOs8oAkeHSRXv2lE539XnadtKnuNRcsLgzyidRU1YMDciZ8?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe03T46EgH7BMYRhTHdCVsJTjCNRTT76UGNI5rh2s8GAUuSNPi3hHBTVuydnDjD3OFahnQcU5MBZ9lO-lLVpv9jTQhodGqK8hrL9wSH6L0iEdgix-hcDeaaMP43JhCJwu4OYTabU1cm0F9o0Fqj5bqZGUdl?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Once the application is running, navigate to <em>http-client | apis.http</em>.</p> <p>You can play around with the REST APIs directly from the IDE itself. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfeZ8XYjicRWiXpy5ypKb64_mm7XFjLpHddzpJSA0b_k5KPNGeSDCaeK8a4FqD514jDp-udpDBU5bmXByrmSbzWPBq8ORXSW1J1TmFb5nqPloQ12jJ_9iFi32T9dWXUFRMv-lYLBdH7LIHzxvUpNvZx-P6D?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <h2 class="wp-block-heading">Diving into K8s</h2> <p>Now that we have developed the entire application, it’s time to deploy the application inside the Kubernetes cluster. </p> <p>The process starts with creating the Dockerfile.</p> <h3 class="wp-block-heading">Dockerfile</h3> <p>A <a href="https://docs.docker.com/reference/dockerfile/" target="_blank" rel="noopener">Dockerfile</a> is a text document that contains a set of instructions for building a Docker image. It defines how the image should be constructed, including the base image to use, the files to include, and any commands to run during the build process.</p> <p>Create a new file under project root and name it “Dockerfile”.</p> <p>Simply follow the steps I’ve outlined to build the Docker image. I’ll walk you through it step by step.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfmy90UN_iJO01TkGC5lGmWzCYIlnJZ6qPVQvnsNh9doFZqL_Qvrmlz4tf47FCnK3Nm7PePtg2EIFNGodGzSOAtfJcPeBqJ4eddzs63dlLlPoy5Gj2wU4eFcnCZ_auU6ilYjjAhQ8_shjekQT--11VZThCG?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfxxOi0BLW_mZftPgg5wQg4iPUpLNqjW7yLiBAJuv0vOFJ7aM2JKjDMYL4I9XXcd_NzJhp7441SUnPStVD9YvKt4EmJQIONReBxR9zP62le_NxTEsXpthyM0CCCx3Qt5DHHbHXdRpOYlQEADQ6jwKH9DMhT?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p><strong><code>FROM golang:1.23-alpine AS builder</code></strong></p> <p>Starts with <code>golang:1.23-alpine</code> as the base image and labels the stage as <code>builder</code>.</p> <p><strong><code>WORKDIR /app</code></strong></p> <p>Set the working directory to <code>/app</code>.</p> <p><strong><code>COPY . .</code></strong></p> <p>Copies the entire current directory (<code>.</code>) into the <code>/app</code> directory.</p> <p><strong><code>RUN CGO_ENABLED=0 GOOS=linux go build -o go_k8s</code></strong></p> <p>Runs the Go build command to compile the application. </p> <ul> <li><code>CGO_ENABLED=0</code> disables <a href="https://pkg.go.dev/cmd/cgo" target="_blank" rel="noopener">CGO</a> (CGO enables the creation of Go packages that call C code).</li> <li> <code>GOOS=linux</code> sets the target OS to Linux. </li> <li>The output binary is named <code>go_k8s</code>.</li> </ul> <p></p> <p><strong><code>FROM gcr.io/distroless/base</code></strong></p> <p>Uses a minimal <code>distroless</code> base image for the final container, focusing on security by excluding unnecessary components. To learn more about distroless images, check <a href="https://github.com/GoogleContainerTools/distroless" target="_blank" rel="noopener">this</a> out. </p> <p><strong><code>WORKDIR /app</code></strong></p> <p>Sets the working directory to <code>/app</code> in the final stage.</p> <p><strong><code>COPY --from=builder /app/go_k8s .</code></strong></p> <p>Copies the <code>go_k8s</code> binary from the <code>/app</code> directory of the builder stage into the <code>/app</code> directory of the final image.</p> <p><strong><code>CMD ["./go_k8s"]</code></strong></p> <p>Sets the command to run when the container starts, which is the <code>go_k8s</code> binary.</p> <p>The final image is kept as small and secure as possible, containing only the Go application binary without any unnecessary build tools or dependencies.</p> <p>Go ahead and build the Docker image. </p> <p>Click <em>Run ‘Dockerfile’.</em></p> <ul> <li>Note: Before running, make sure the Docker daemon is running in the background. For this tutorial we are going to be using <a href="https://www.docker.com/products/docker-desktop/" target="_blank" rel="noopener">Docker Desktop</a>.</li> </ul> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfRAg3OEcig7iBc2XFwmu8iYMxvqwRowLDzSJJGptmcUgbXJhrxJRMkUe234g23LkUgs8NQ0YbPf85LqCirLj6Vx47fV4wKsghIrn65fl7mTvYo1I8snid_pp6kbnv2vybE2c8vmjX_KsPc_PeWLonZ37M?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Once the image is successfully built, push the image to the Docker registry.</p> <p>Right-click the image tag and select <em>Edit Configuration</em>.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfsVn49fHboN0sOxsQYny4MLx_utBSWdov6pEB6JRR1TpRDe3V7bBBLM9rIg_nrhrUswljWh_1fNZV6pgJcSNx9Vv767kvr2pq4LBbOB0qRlNeliHqMrPxFGYPYVDxLl7TBGZGzEu50SOyXX-dFobXMXdtL?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Provide the image tag and apply the changes.</p> <p>Note:</p> <ul> <li>Before pushing, make sure to change the image tag based on the Docker repository which you have created in <a href="https://hub.docker.com/" target="_blank" rel="noopener">DockerHub</a>.</li> </ul> <ul> <li>The image tag should follow the format <code><hub-user>/<repo-name>[:<tag>]</code>. Follow the steps to create <a href="https://docs.docker.com/docker-hub/repos/create/" target="_blank" rel="noopener">repositories</a>.</li> </ul> <ul> <li>In this example, the tag <code>mukulmantosh/go_k8s:1.0</code> is for demonstration only and may change based on your account type. Here, <code>mukulmantosh</code> represents the user, while <code>go_k8s</code> is the repository name and <code>1.0</code> is the specified tag.<br></li> </ul> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdG9gU3HhHpdDSqYwWO3AWGvWMCoSAWucqy3XDbClvBZaSBLO928KI0HqmA0ndWE13JrsXUgnzQSh994Uzr4ndBIjADqiY8ndXQ3riDFwcyoTk3Yfql4teypc-nIXbWbHxXbPNha_wm9KezOrVfQh1sG5s?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Make sure to re-run the build process. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXerB5km4c37rBP78ajWouxY4QzzrgfF8nEe4It128HhTEPLxPldtJhdSSjLVeDl-b3-aitiJ-lmp0N28kQxpz7d8a0oFkQK0Q5aWGatZwgUpiL29zs70dEM3XcwjbrVxnFQmI6e6QAFdOvwZBnsmi6ZuH6j?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>You can see that the image tag has been applied. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdQcxnwe-vAvnHpGBuxQP091YCIvuKXgo4DgB_bcXBfbIX9IoPXG9EvqSbhpzlQCYrr5mqTA02FSFdhVSy1Tj05Tug-PofpS8nYffAFbG3YnCwy47gVw03cxmvCweaexxgDmFDQQ6O8qtKvKYrE1uxvEXim?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>It’s time to push the image. </p> <p>Right-click on the image tag, then select <em>Push Image</em>.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfCANtYXPN_tSDnI1ac-b9ZIEVjCra9Kgn3e7KdvCyl8SrmTYoJNsLIuR2x2yyBfpKx6PV3LO6gW2pJAialbVbuiDLh6MnORWY1vw4bKMIY0-PurNCJn8SfCyZdfLMckvMeX4GZio4oU37vEqg7L2tmCyg?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Click <em>Add</em> and provide your Docker registry information.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfJEDwK6HfcjcbJL543ZUB77J3QDR-ovW8cFWAuAAJrnWmjHHpfIrrGPmhKJR4uQk8RrxhEK0D0PtC4eFTSlpbB8HjISxYGAeUlyXaMeQ729isTpFJBbGwDn6IMXUQSOKTT8dPnGBL38-T0xOch9GA2qB96?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeWTb56QRmhFycGWHHv6yADQUhnbQd55-bJJadBtmjkanPG5ShD7b0kMqUD3tW12FZ0poLGEix-sxcdR8KagILKvuWkGmsKyNSkOL4UaetC_at7-eajCfnWqQuUY6gIPQlSJlCG7EaA8i9JtmowQtFgXEvT?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Once successfully authenticated, click <em>OK</em> to push the image.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcmic6L7PrNOZ8MZHLOox8E3Wl_jTvlKND3PcqiOhdUKHJJ241gtN12QOpglElyFHsIhcypqgacbBJ8Vwr7d3Zqo6oJ1yMGz96n_gh8SYaJLEnskcb7nRo7Y4jVOn4TSXjM78NBI3NqSBiur29SlG5Qh66t?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Once the image is successfully pushed, you can observe the changes in DockerHub. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcKtKkx_VSfLmAJq2rbMHTza5QcRfL8DM6-0_wQwf4KX9L23t0t7JeFSHnDW-LZsADxvhmuAV6efUTIpyqOT_miXxr9G0gkVnopvDuscuuDv7YlBzz-kmaSu5eUKYqYsuZXUwRBhpYM0VH75IWu?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Well, the image is built and pushed. Now it’s time to work on the second part – writing the Kubernetes YAML files. </p> <h3 class="wp-block-heading">Writing K8s manifests</h3> <p>This part of the tutorial covers how to deploy applications to local Kubernetes clusters.</p> <p>In this tutorial, we have utilized Docker Desktop, though you can also opt for <a href="https://minikube.sigs.k8s.io/docs/" target="_blank" rel="noopener">Minikube</a> or <a href="https://kind.sigs.k8s.io/" target="_blank" rel="noopener">Kind</a>.</p> <p>If you’ve chosen Docker Desktop as your preferred platform for running Kubernetes, be sure to enable Kubernetes in the settings by clicking the <em>Enable Kubernetes</em> checkbox.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdji9YwtTdr2c6Splr-Rq2ZLcWY_8m4lDYR3sd3CPukZLqocKqiw0wPX51y9wkQtFm8ilJoDdSd7yEDRQm-Rr-qFDnPyODbBFL_mOWzyKo2-FpvMRwcuSsSKlGmQ4blWVqccC2si_40ckafait2cCqUQWkX?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Once Kubernetes is up and running, it’s time to create a namespace.</p> <h3 class="wp-block-heading">What is a namespace?</h3> <p>In Kubernetes, a <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/" target="_blank" rel="noopener">namespace</a> is a logical partitioning of the cluster that allows you to divide resources and organize them into groups. Namespaces enable multiple teams or projects to share the same cluster while maintaining isolation and avoiding naming conflicts.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1100" height="355" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/namespace.webp" alt="" class="wp-image-529029"/></figure> <p style="font-size:12px;">Source: <em>belowthemalt.com</em></p> <p>Begin by creating a directory called <code>k8s</code> in the root of your project.</p> <p>Next, create a new file and name it <code>ns.yaml</code>.</p> <p><strong>NOTE</strong>: A Kubernetes manifest is typically written in YAML or JSON format and outlines various parameters for the resource, including its type, metadata, and specifications.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXc2jrG9PCtguS3_Fw-UgNG2DB1wAoBQV30Dt712KemelSdv7YG2yEu3sYKfX1j-obgOVZYdb-NJe07Nu8Sw6hYfbuk-ihFaJ4bbGtjSBkkFyo1AES3ayyOG416ZlGBla8oCITJzd1K_bmSJ_kAn0FPK7wdP?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>This YAML file would create a namespace named <code>go-k8s-demo</code> in your Kubernetes cluster.</p> <p>Let’s break it down.</p> <p><strong><code>apiVersion: v1</code></strong>: This specifies the API version of the Kubernetes resource. In this case, v1 indicates that the resource is using version 1 of the Kubernetes API.</p> <p><strong><code>kind: Namespace</code></strong>: This indicates the type of Kubernetes resource being defined. It can be Deployment, Service, etc.</p> <p><strong><code>metadata</code></strong>: This section holds metadata about the Kubernetes resource. Metadata usually includes details like the name, labels, and annotations.</p> <p>If you type the following command in the Terminal, it will show you lists of the API resources available in the Kubernetes cluster. </p> <pre class="EnlighterJSRAW">kubectl api-resources</pre> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXd8JU7ujaUvWAQktoIwRrq7cWEGVlJ4Y_5UfDdv1gLbcCjlWsyiPSIzhBQGM16zEcaipnafhx_m5YKG_Aw0ALhOOXXnd0oPuLnqQrlSgz1F5lESAgw4D8VUcsAS7xXALjben_pnM5sFrMkC7rF1n3MzYgJo?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Okay – you’ve created the YAML file. Now it’s time to execute it. </p> <p>There are two ways you can create a namespace:</p> <p>If you prefer using the Terminal, you can run this command:</p> <pre class="EnlighterJSRAW">kubectl create ns go-k8s-demo</pre> <p>Or, you can apply a file by running this command:</p> <pre class="EnlighterJSRAW">cd k8s kubectl apply -f ns.yaml</pre> <p>Both methods will create the same namespace.</p> <h3 class="wp-block-heading">Creating a namespace with GoLand</h3> <p>You also have the option of doing this in GoLand. Yes, you read that right, you can play with your Kubernetes <a href="https://www.jetbrains.com/help/go/kubernetes.html" target="_blank" rel="noopener">clusters</a> directly from the GoLand IDE. </p> <p>As a side note, if you’re using GoLand 2024.2 or later, the Kubernetes plugin is already bundled with the IDE, so you don’t need to install it separately.</p> <p>Open the <a href="https://www.jetbrains.com/help/go/services-tool-window.html" target="_blank" rel="noopener"><em>Service</em> tool window</a> by going to <em>View | Tool Windows | Services</em>.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdASRlLRCWkeGbXe45dOS4unUOSIsI1s4iz1bg1H5I8HLIAoBZQ5meIaYY-NwWQf8KyWG_K_7Qq6mnSh01g5jO8CA8YuNde8Q_N-AwcrWkvINWWxWxaodgzfBqAi4dPJWtaSGpfMUCUIMwbh-OoFSUMpAxE?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Right-click on <em>Kubernetes | Add Clusters | From Default Directory.</em></p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcBgAAb_XBbWtmIZVEbj0ha_Ha1j8f1KV8sQSDBEW0lb0YddE-7dE8mMce9Sm1nYyjZhRKy5mueN3pKICtnZaW0fE947d7A1zW7_F_YZtHHZPZLBK7hn5oElVf2zdwrBWBsKfBAkQP-D_xZ4jo3LSBMz5HY?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Select <em>docker-desktop</em> and click <em>Add Clusters</em>.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfAp-DjDjWPQ_gEo27QWcodvQPZKq0hffdbeh-O2Aqoo0hCJLBw7KmZDVHZG7Fp2hpFXfE3mfGsuO1CTuw8Vq6aPzIHVTwcaOHainS685rsDQ1n9_uYD_6wr__tF2JUXbOibgtzoRWNiRJeF16-0xjW_8U?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>You will see docker-desktop as your newly added cluster. Click the play icon to connect to it.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfDrzvwlWjGjq9ZTFNQImLnZj9oVd9AU2x2Aqx4Jk8Ie3milAtm2pT0jFUJWAcRydtqixa8dG_k-7_b4RGjoCYVFqwXlNyzneZ4_FMaVkl0yX2kxRnhz4w9sNzGzuIsgmyV2ku7jb0QtwUfSszYYeg1NCrk?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe7ZlDcgjtBd8PnuQHEx23x2tqJaswlu3QhpXG-KNXRwHz9sS5Pi_f2u8i36aPdEaWwpCKcIknicROoXZAmg2y1wmAig2H5pdXkjuUdcMeCmPP34irTgaTvN93KoA9NKH_-6drfMzPtDFQT5LffrHtHFBqn?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Return to the YAML file and hover over the top right corner of the screen and click <em>Apply to Cluster </em>to set your cluster to docker-desktop.</p> <p>Once done, apply the changes.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdggNgnTAVfZXg2BxAmaI4KjGBIJHiSuwXxfpMq8nTJ-E4I0qwZ-JHf57IORqjdFggCFW_pU76Qp633Ct8ySpOe6HflC2G6XmepH1viNJ0fggCzETWMpbTZe9hkT-hUEJEVE_cc7yY_JXyRMg31XacQQ1IE?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>The namespace is successfully created. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfK2_GCFvXOYNkWZ6AoF0R12LIb04mZ7o1L4RpeZEB3Odhm2D2flsNudV3ue7iZK3Qf0Z7QuTpYgKhAC4mGZmDccRzJCQR6Faon1W3oBB49OM8iSx3RkrlIYil9FC55PIUx8RPjukmt1Wxhum2qFeYUyuna?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>We will now switch to the newly created namespace to easily view the applications running within it.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXelXpQWMAmreJp8dCDFdxvGX4LOT-d5jwZauJjkDYn-ZunGuq9pGzNxRSnIrBCRZfnJAiEBgteJ3uBJwxWW0Jzg841XdHf8Pj5KkgzFsElQ1H0x3-u5nMgNkmokrQCWPkTgq7sQWPnzxpi4qbZc8f09Fh0?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdrFYbt57lGUhQJWJLu0ToGQN7db_uVJaMSrngiVM-uwpGp29rkPo1fP_4pC4y0u3Fb26DbqeI_kbXhsYKc8O_0Jb_w_VUxio2_Lhu_pMNX1wMN9_SEZ0GZYH0nieop1YFEExk3x9GfwwAJ72oCSbv1ATY?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>You might be asking, “This works with a local cluster, but what about connecting to an external one?” Good news! You can do that as well.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdHT3A9-wjYDKNtJdlI1ICLeX-Ukn82hSX8x_iIEbfSrrCAVSKS7HmGxI1AFqnvr7A2_JQe1AyC-AnBMTj26FEIqksFwF7EumeQl2ix4mqofMW2qeOZcHkjrhcYaRjKE43OolvwETk_ppoSsL5D8YLaw_RD?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>You can also modify the paths for the kubectl and helm executables. Additionally, you have the option to customize Kubernetes configuration files at either the global or project <a href="https://www.jetbrains.com/help/go/kubernetes.html#multiple-kubeconfig" target="_blank" rel="noopener">level</a>.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcftpSapD2tODPlODnlMcMsUrJhKYmB-832hi-19TSDLx9u8BJgLMl_FRmtZDPF9PpGTRqm5V5tNfRItTT-x0MamlfiPoDaSmwhJt0ZT2I71EWOnQsrjDl9HvipkXBEEM1qETrh4ugAMkMFjmHvX-QF5TX9?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcEGHdqJ2JttQE98ol8heubZjJQQZi4c3t7oiczEfk2tAc9_qK1Ms7j7YCqo8jOWxvLtb69jj8hGcNly0t_I1aNhBX3H_5F1mQ4DLxzIXPgqcKeqf87Ikuqs2BGQU898Sp4lBH96IfUcFzEImprGrku9d4?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <h3 class="wp-block-heading">Database and K8s</h3> <p>The namespace has been created. Now let’s start working on the database.</p> <h4 class="wp-block-heading">PersistentVolume</h4> <p>We are going to create a <a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/" target="_blank" rel="noopener">persistent volume</a>. A PersistentVolume (PV) in Kubernetes provides storage for your application’s pods. Think of it as a storage space that exists independently of any specific application.</p> <p>Unlike regular storage that disappears when an application stops, a PersistentVolume retains the data, making it suitable for applications that need to save files or databases.</p> <p>Create a new folder called <code>db</code> in the project root, and then add a new file named <code>pv.yaml</code> inside it.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeQDowMgudS0tN7B1u9yM8Ps3TTGXea6lkonge0-uvjgW6psK35GjCCxMd4IbaRnP7CeODrr5LtRZiv9YdFsREcJqAf2vaKEqu9e_ESGCKhHMcnNX9iURWdrTlW_H93ad3unzcpq5pf0yJV0LaC6xUq7fA?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>This YAML configuration defines a <code>PersistentVolume</code> named <code>postgres-pv</code> with 1 GB of storage. It is associated with the <code>postgres</code> application and can be accessed as read-write by one node at a time. The volume is stored locally on the host at the path <code>/data/db</code>.</p> <h4 class="wp-block-heading">PersistentVolumeClaim</h4> <p>Create a new file called <code>pvc.yaml</code> under <code>db</code>.</p> <p>A <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#create-a-persistentvolumeclaim" target="_blank" rel="noopener">PersistentVolumeClaim</a> (PVC) in Kubernetes is a request for storage by a user or application. It allows you to specify how much storage you need and what characteristics it should have, such as access modes (like read/write).</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXct7G2hx6pfBI8cY6FHXnvkUF9yZ30avMWUqlDL4NlcanuwxsZ3bYfX_X3_hlutQ0J976hyq_s7B8ZPhmcInbY1EP-2VcfaZPyCKKLmQVHNyl9OQ2knaYVqxzFilyJsTIhF64gCS9tYwgyipP0HrPtHkexX?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>In this YAML configuration we are creating a PVC in the <code>go-k8s-demo</code> namespace requesting 1 GiB of storage with a <code>ReadWriteOnce</code> access mode using the <code>manual</code> storage class.</p> <h4 class="wp-block-heading">ConfigMap</h4> <p>Create a new file <code>cm.yaml</code> under <code>db</code>.</p> <p>A <a href="https://kubernetes.io/docs/concepts/configuration/configmap/" target="_blank" rel="noopener">ConfigMap</a> in Kubernetes is a resource used to store configuration data in a key-value format. It allows you to separate configuration from application code, making it easier to manage and modify settings without needing to rebuild your application.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe_7ymPcLUB5U43RUtEocotRcOyhRaWBki32TLN4z6wBMm9EDigz2ekiuGqDdBAxkEGGD3BcWQ8G_woYQRFwPSU6xS_3IEg5O1Hdh5mUPUmfQ8sSJpr4z-hS5X4UKpDD_2KXj0QNeA9KTs6vof_TsWyNAud?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <h4 class="wp-block-heading">Deployment</h4> <p>A <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" target="_blank" rel="noopener">Deployment</a> in Kubernetes is a resource used to manage and orchestrate the deployment of applications. It allows you to define how many instances of your application (called Pods) you want to run, and it ensures that they are running as expected.</p> <p>Create a new file <code>deploy.yaml</code> under <code>db</code>.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeUFeCdvpbDJK8AdH2r4ATePHuuVuuDv0LHNTLrAoQmQ3-I8AtGYlDWDCtOdOtP2-qy_fAwUQHyhGx5br48AuLZmt-RNJzOxSvGa8BM6fA0a7XkEJCwdPuVNcKAFU-bSRV4WbzKzIQ9reF9Bl8s8m307qqJ?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>This YAML file defines a deployment of a single PostgreSQL container running version 17.0, which exposes port 5432 and runs only one instance. It loads environment variables from a <code>ConfigMap</code> and uses a <code>PersistentVolume</code> to store data. </p> <h4 class="wp-block-heading">Service</h4> <p>A <a href="https://kubernetes.io/docs/concepts/services-networking/service/" target="_blank" rel="noopener">Service</a> in Kubernetes is an abstraction that defines a logical set of pods and a way to access them. It provides a stable endpoint for your applications, making it easier to communicate with groups of pods.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdpBp6StvtyQDkYxFBKAYJosdo2sZfzdq4ESWcc2Do1omrxIvREfxWsao3JeUT4L8XeZwZCqdFdzHAa5twRYyyyrLjo4vBXAbpUDu1wgs_VJY4--Oqi0B4b41f_XF1SN2Uy7tOTycYGJPr15WUaCyNgk5Q?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p style="font-size:12px;">Source: <em>kubernetes.io</em></p> <p>Create a new file <code>svc.yaml</code> under <code>db</code>.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcE1FqtzBj9dwblVzkVF0fd7jh3pTmchm2XVrkN8VVSokZNnH81X1P8VR_X0qFexMUTc86xp4vTuO7AOqqdSxz60vw0HOxAAEoWr52lVV167NoDkpYQ9-AnKr4LNdoXKVSijiR_O13GjhkR_YiH-1N_YUwH?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>In this YAML file we have defined a Kubernetes Service named <code>postgres-service</code>. The Service exposes port 5432 and routes traffic to the pods labeled with <code>app: postgres-db</code>, so it will allow other applications within the cluster to connect to the database.</p> <h4 class="wp-block-heading">Launching DB</h4> <p>We now have all of the configuration files needed to start the database. Let’s execute them.</p> <p>There are two methods to do this.</p> <p>First, open the Terminal, navigate to the <code>db</code> directory, and run the following command:</p> <pre class="EnlighterJSRAW">cd db kubectl apply -f .</pre> <p>To see the current status of your pods, you can run the following command:</p> <pre class="EnlighterJSRAW">kubectl get pods -n go-k8s-demo</pre> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdUizRxGAfJBXKkojbP_ll9rwvWtvCWiKAzIS-aroKVpQsxK7NuM6A8hhZoGhGjGcTn0sNFHd1V3kA4ZiFCFwNhFzf3HCHV3jVJOXNAR3PbuBiUrNWWzRurJLJ6a9JH8aKmBx3_r1_88-U-ht4tc1Gx4eOj?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>The second option is quite easy with GoLand. You don’t need to remember the commands – just the follow along with the video below:</p> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/goland_k8s_1.mp4"></video></figure> <h3 class="wp-block-heading">Application and K8s</h3> <p>Now that the database is up and running, it’s time to prepare our backend application.</p> <p>Begin by creating an <code>app</code> folder inside the <code>k8s</code> directory.</p> <h4 class="wp-block-heading">ConfigMap</h4> <p>Create a new file called <code>cm.yaml</code> under <code>app</code>.</p> <p>Enter the required database credentials.</p> <p><strong>NOTE</strong>:</p> <ul> <li>Grab the credentials from <code>db/cm.yaml</code> that you defined earlier when creating the database pod.</li> <li><code>postgres-service</code> under <code>DB_HOST</code> refers to the <code>db/svc.yaml</code> service we created earlier.</li> </ul> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXexSfcnunENGdnpjr3xoOMLZUtlKJy6mBfVJF7u5TByDiIxaa_o8Z2LUQh2qp9nSosu4ac2Z0RXCEN5gCQRxH3pXjYrltX9RBT-Y5rwwkmGkjNwrdXMAMQW3rMG72dj1Cx5ndQv8qGFx5f55OlXS5qugKYg?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdV7D4yJl_kkha9X1sJMtrTCiiWP_Xe-3eKMWuXdbTz2AUwZrS585E20tonemFV-Olsuw_DQiMlxeB7jDPkZOyF0FmoBXYG8mKiHxvLNbzA5xNFSYKKKQFkbXcGWMBHqmyOC3yNXCNC7Vi9Rv9lUVJn5KOg?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcR9qyhU6MiyDIT7ZW8y5gWlefgjT89AOWGgzXaK1fV9u06QmzgruvfC3DZXlvHE4RRnjzNExzoDnV4eAg3aHYFLsmKWmM-uvtYTkHTHkLh6Bekavf5KyEPOuRwBEl58gQ5aqGhbn8Ga_mL9frAZTS3ffE?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <h4 class="wp-block-heading">Deployment</h4> <p>Now let’s move on to the deployment. </p> <p>Create a new file called <code>deploy.yaml</code> under <code>app</code>. </p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXevgfcDz4-lInG7z_4BO3oFDRyVlF7QdqwFitAh8ocXbOH05A8S4dxee-4f7bgrxq_fFv4kRM5iyfn9BO6xGedQvW7UOXe3eK4zh1gFt5wKblbBwTCzyBCxXjSgb4dYGBNyt-9z3w6NG5S6UjG8Z7NjA1yP?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="2080" height="2604" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/deploy.yaml_.png" alt="" class="wp-image-529098"/></figure> <p>In this YAML file we define a Kubernetes deployment that runs a single replica of a pod, which contains a single container using the <code>mukulmantosh/go_k8s:1.0</code> image. The container exposes port 8080 and gets its environment variables from a <code>ConfigMap</code> named <code>app-cm</code>.</p> <h4 class="wp-block-heading">Service</h4> <p>Now let’s wrap up the last file. </p> <p>Create a file called <code>svc.yaml</code> under <code>app</code>.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXesGbO34PVXCcZG6_HEPccSmwrBWjqE4OgqpEr2EaI7tfPpw6XO5cUndBM7KGyyhN7PDwUGvgkvXuUq4--DUmhjZ3Eew0AJOvyhSGGkbZvkHKPsy586keatOQ2lgATw9EvbAHlg_fytdpzO-kAdZ-KDIlvt?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>To summarize, we set up a service named <code>app-service</code> that allows external traffic to reach your application running in the cluster through port 30004. Requests received here are forwarded to port 8080 on the application pods.</p> <h2 class="wp-block-heading">Testing</h2> <p>Now let’s deploy our application and start testing it out. </p> <p>The process is going to be exactly the same as what we did for the database.</p> <p>Navigate to the <code>app</code> directory and run the following command:</p> <pre class="EnlighterJSRAW">cd app kubectl apply -f .</pre> <p>Alternatively, you can do this in GoLand, which is quite easy and straightforward. </p> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/goland_kubernetes_running_part2.mp4"></video></figure> <p>You can also check the status of your application by running the following command:</p> <pre class="EnlighterJSRAW">kubectl get pods -n go-k8s-demo</pre> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcSEcrj33nwQf4hfv6QT8KPF375aHu1Pp0BTbMPSPbwwPXyMHC230G_3SRuMWj-vEXcuAq-mYqHPwv3qQXlOr6qMMnUfR-veEEkWGNOoBUOW1JbTzhwaSjjGGc_99im9_kLnsfot3X7tMNtmzLhFl_PbQIC?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>Let’s test out the application by sending an HTTP request.</p> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcIJcqpBl0oqePspHJtP_7CKbHsdPCcxWTpjfEmVvdCjxahLdA6UxLwgyeB2BUBquAyHCiC1Nk8bu6orvPAWtazvQgvib9NsmybkWGyRw3I707TTz7YKq3cJ3SODw3qNmYyvsqzDJOvFii_ntRlWIhOAVQ?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <figure class="wp-block-image"><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXduTIEWbee186g2PNiP90ipZSbDZSRlrXZFi-owt11fB3Hb7g8Z07JB5zXWzw8V_BNGbBjohvBDnKS6tlq2iwqA4X6INb6hb6_CUmOL3biasuzwIEu69pMGHAWsJOr17kpxNanBtGlThoWGm5nIyVST2XVS?key=cmOOFmren0-Yj2IOP4a1eg" alt=""/></figure> <p>The application works!</p> <p>This was just a brief demonstration of how to use Kubernetes with Go, but there are many more possibilities to <a href="https://www.jetbrains.com/help/go/kubernetes.html#create_resource_file" target="_blank" rel="noopener">explore</a>.</p> <h2 class="wp-block-heading">References</h2> <p>If you already have a strong grasp of Kubernetes and want to learn how to deploy in a live cluster, take a look at my <a href="https://medium.com/google-cloud/deploying-go-api-on-gke-google-cloud-9cec676bb3a6" target="_blank" rel="noopener">tutorial</a> on deploying Go apps in Google Kubernetes Engine.</p> ]]></content:encoded> </item> <item> <title>State of Kotlin Scripting 2024</title> <link>https://blog.jetbrains.com/kotlin/2024/11/state-of-kotlin-scripting-2024/</link> <dc:creator><![CDATA[Anton Yalyshev]]></dc:creator> <pubDate>Tue, 19 Nov 2024 16:07:29 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/Blog-featured-image-1280x720-1.png</featuredImage> <category><![CDATA[ecosystem]]></category> <category><![CDATA[news]]></category> <category><![CDATA[kotlin-scripting]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=kotlin&p=527650</guid> <description><![CDATA[Update: we made some updates to the original post to accurately reflect the state of Custom Scripting and to avoid misinterpretations. TL;DR: Kotlin scripting remains an essential part of the Kotlin infrastructure. We continue to support it in the experimental state, and we are concluding certain experiments and reducing the number of scripting-related technologies that […]]]></description> <content:encoded><![CDATA[ <p><em><strong>Update:</strong> we made some updates to the original post to accurately reflect the state of Custom Scripting and to avoid misinterpretations.</em></p> <p><em>TL;DR: Kotlin scripting remains an essential part of the Kotlin infrastructure. We continue to support it in the experimental state, and we are concluding certain experiments and reducing the number of scripting-related technologies that we provide and actively develop.</em></p> <p>Kotlin scripting is the technology that enables executing Kotlin code as scripts without prior compilation or packaging into executables. In addition, several extension mechanisms exist to facilitate the usage of Kotlin for specific applications, such as configuring build tools. On top of that, REPL functionality, which is closely related to scripting, is available for Kotlin in various forms (including, for example, <a href="https://kotlinlang.org/docs/kotlin-notebook-overview.html" data-type="link" data-id="https://kotlinlang.org/docs/kotlin-notebook-overview.html" target="_blank" rel="noreferrer noopener">Kotlin Notebook</a>).</p> <p>All these technologies can be found in Kotlin and other JetBrains projects. Some of them are well known, others are barely used, but all require a noticeable amount of attention from the team.</p> <h2 class="wp-block-heading">The evolution of scripting in Kotlin</h2> <p>Scripting was introduced into Kotlin long ago as an experiment to investigate new ways of using the language. Since then, the development has been driven by the demand of external and internal adopters, as well as some experiments born inside our team. Over time, we accumulated a lot of functionality related to scripting in our codebase, and the effort required to support it grew quite significantly. Therefore, at some point, we started to review the functionality we have, how it is used inside and outside of JetBrains, and how we can distill it into a reasonable minimal subset that we are willing to support and develop without breaking too many existing use cases.</p> <p>This blog post attempts to summarize our findings, explain our decisions, and outline the future directions in this area. We hope it will clarify the future of scripting in Kotlin and give the community a solid basis for making technical decisions. </p> <p>While we already have a firm roadmap for the immediate future, we welcome and appreciate your feedback and ideas for further improvements. We are especially interested in hearing about any particular use cases for scripting that you may have. We encourage you to use comments here or create <a href="https://youtrack.jetbrains.com/issues/KT" target="_blank" rel="noreferrer noopener">YouTrack issues</a> describing your scenarios and how the announced changes may affect them. Your insights are invaluable to us and will play a crucial role in shaping our future plans for the language’s development.</p> <p><p align="center"><a class="ek-link jb-download-button" title="Contribute Your Feedback and Ideas" href="https://youtrack.jetbrains.com/issues/KT" target="_blank" rel="noopener">Contribute Your Feedback and Ideas</a></p> <h2 class="wp-block-heading">Basic scripting</h2> <p>We conducted some research into scripting usage in the past and concluded that besides a few main adoptions, like Gradle build scripts, there is a relatively small number of known uses for scripting and REPL. This might be attributable to various factors, but the result is nonetheless clear: The functionality is not as popular as we had anticipated.</p> <p>Some technological problems could (and will) be addressed, but there are some inherent issues with attempting to position Kotlin as a scripting language. </p> <p>In particular, Kotlin is not an interpreted language, and it cannot achieve the user experience typical for dedicated scripting languages. To achieve the current script-like behavior, we compile the code under the hood. The compilation process is quite intensive because the Kotlin compiler was not designed for such scenarios. </p> <p>That is why we made the following decision:</p> <p>Although we will continue to provide generalized support for scripting in Kotlin, which includes compilation and evaluation of basic `.kts` files, as well as custom scripting (more about this below), we are not prepared to recommend Kotlin scripting as a generally applicable scripting solution, for example, as a replacement for Bash or Python.</p> <p>On the other hand, we believe there are many new usage scenarios where, despite the known limitations, the use of Kotlin scripting could be beneficial. There are also several other potential use cases that we would like to explore further.</p> <h2 class="wp-block-heading">Custom script types</h2> <p>The most powerful scripting solutions require extension mechanisms that allow for the customization of script compilation and evaluation. One of the most prominent examples is <a href="https://docs.gradle.org/current/userguide/kotlin_dsl.html" target="_blank" rel="noreferrer noopener">Gradle Kotlin DSL</a>, where the Custom Scripting API is used to bring Kotlin language with traditional Gradle DSL to build scripts. This brings us to the second decision:</p> <p>We will continue to support the Custom Scripting API (an unofficial name for a set of APIs for customizing script compilation and evaluation, as well as APIs for embedding script hosts into third-party applications). Therefore:</p> <ul> <li>We are concentrating our efforts on improving the user experience with a few known use cases, in particular Gradle Kotlin DSL and select others.</li> <li>Outside these use cases, the API remains in the experimental state. Hence, things like documentation and IDE support for generic custom script support may continue to lag behind.</li> </ul> <h2 class="wp-block-heading">Main.kts</h2> <p>In addition to the basic and custom scripting, we would like to continue supporting `.main.kts` scripts. The `.main.kts` scripts were initially developed to demonstrate the utility of the Custom Scripting API. However, with its support of dependencies and other features, it was adopted by many users as a default Kotlin scripting solution. Therefore, the next decision is:</p> <p>We will continue to develop the `.main.kts` script type, which is already helpful for simple automation tasks. We have plans to extend its functionality and streamline IDE support. Such scripts continue to be supported out of the box in the Kotlin compiler and the Kotlin plugin for IntelliJ IDEA.</p> <h2 class="wp-block-heading">Kotlin REPL</h2> <p>The default REPL implementation has been a part of the Kotlin compiler (`kotlinc`) and Kotlin plugin for IntelliJ IDEA since the first release. Still, the functionality is limited, and improving it was never a priority for the team. Therefore, the user experience is not on par with the general Kotlin user experience in IntelliJ IDEA. We made several attempts to spin off alternative REPL implementations (e.g. the <a href="https://github.com/Kotlin/kotlin-interactive-shell" target="_blank" rel="noreferrer noopener">Kotlin Interactive Shell</a>), but unfortunately, these never gained enough traction.</p> <p>Meanwhile, we are improving the <a href="https://kotlinlang.org/docs/kotlin-notebook-overview.html" target="_blank" rel="noreferrer noopener">Kotlin Notebook</a> plugin for IntelliJ IDEA, which offers a smooth, extensive, and interactive experience working in Kotlin. With Kotlin Notebook, you can develop and experiment with Kotlin code, receive immediate outputs, and visualize data. We believe that it is an excellent replacement for all our current REPL solutions. </p> <p>Besides that, IntelliJ IDEA provides Kotlin <a href="https://www.jetbrains.com/help/idea/scratches.html" target="_blank" rel="noreferrer noopener">Scratch files</a>, where you can quickly prototype your code. Therefore:</p> <p>We plan to sunset the default REPL implementations in the Kotlin compiler and the IntelliJ IDEA plugin.</p> <ul> <li>CLI REPL (via `kotlinc`) will continue to function at least until the release of Kotlin 2.3, but its operation will be limited to compatibility mode, i.e. with the `-language-version 1.9` option set (and may require an opt-in flag starting from release 2.2). </li> <li>The default Kotlin REPL in the IntelliJ IDEA plugin will be removed in one of the next IntelliJ IDEA releases. </li> </ul> <p>We will continue to promote the Kotlin Notebook plugin and IDE Scratch files as solutions for interactive Kotlin development.</p> <p>This decision places some uncertainty on the external REPL implementations, like the Kotlin Interactive Shell. Although we plan to keep some REPL-related functionality in the compiler and Custom Scripting API (not least because solutions like Kotlin Notebook rely on them), with a final switch to the K2 compiler, a significant portion of this functionality will be changed or dropped, so it may require substantial effort to rewrite such implementations to the changed APIs. </p> <h2 class="wp-block-heading">Other technologies based on Kotlin scripting</h2> <p>Besides these main areas, there are a few other related technologies and APIs for scripting that we are currently supporting. We believe the cases explicitly mentioned above cover a majority of possible user needs. Therefore, we plan to drop most other scripting-related components and libraries from the compiler and IntelliJ IDEA. In particular:</p> <ul> <li>JSR-223 support – considering that the original <a href="https://jcp.org/en/jsr/detail?id=223" target="_blank" rel="noreferrer noopener">JSR</a> is in the withdrawn state, we do not believe supporting the de-facto obsolete API makes sense. The existing implementation will continue to function at least until the release of Kotlin 2.3 in the language version 1.9 compatibility mode (but we may consider renaming the artifact to raise awareness of the planned changes), and it will be dropped after that.</li> <li>`KotlinScriptMojo` – a Maven plugin that supports script execution during the Maven build. We did not find evidence of enough usages to keep maintaining it, so we plan to drop it in one of the next Kotlin releases.</li> <li>`kotlin-scripting-ide-services` – a library for implementing code completion functionality, mainly for REPL implementations. It is currently used in projects like Kotlin Interactive. It is heavily based on the infrastructure of the pre-K2 compiler and cannot be easily ported to the K2 version. Therefore, it will most likely stop working around the release of Kotlin 2.3 and will be removed from the codebase. We may consider reimplementing similar functionality on top of K2 in the future, but for now, this is not something we are actively pursuing.</li> </ul> <h2 class="wp-block-heading">Moving forward</h2> <p>We hope the focused approach will allow us to move forward and provide a better experience with widely used scripting technologies. At the same time, it will free some resources for exciting language features and applications. We encourage you to share your use cases for scripting and appreciate your feedback on these changes and how they may affect your work.</p> <p><p align="center"><a class="ek-link jb-download-button" title="Share Your Feedback and Use Cases" href="https://youtrack.jetbrains.com/issues/KT" target="_blank" rel="noopener">Share Your Feedback and Use Cases</a></p> <h2 class="wp-block-heading">What else to read</h2> <ul> <li><a href="https://kotlinlang.org/docs/kotlin-notebook-overview.html" data-type="link" data-id="https://kotlinlang.org/docs/kotlin-notebook-overview.html" target="_blank" rel="noreferrer noopener">Kotlin Notebook – documentation</a></li> <li><a href="https://blog.jetbrains.com/kotlin/2023/04/kotlin-dsl-is-the-default-for-new-gradle-builds/" data-type="link" data-id="https://blog.jetbrains.com/kotlin/2023/04/kotlin-dsl-is-the-default-for-new-gradle-builds/" target="_blank" rel="noreferrer noopener">Kotlin DSL Is Now the Default for New Gradle Builds</a></li> </ul> ]]></content:encoded> </item> <item> <title>Code Faster with JetBrains AI in PyCharm</title> <link>https://blog.jetbrains.com/pycharm/2024/11/code-faster-with-jetbrains-ai-in-pycharm/</link> <dc:creator><![CDATA[Helen Scott]]></dc:creator> <pubDate>Tue, 19 Nov 2024 15:25:51 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/pc-featured_blog_1280x720_en.png</featuredImage> <category><![CDATA[ai-assistant]]></category> <category><![CDATA[productivity]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=pycharm&p=527669</guid> <description><![CDATA[PyCharm 2024.3 comes with many improvements to JetBrains AI to help you code faster. I’m going to walk you through some of these updates in this blog post.  Natural language inline AI prompt You can now use JetBrains AI by typing straight into your editor in natural language without opening the AI Assistant tool window. […]]]></description> <content:encoded><![CDATA[ <p>PyCharm 2024.3 comes with many improvements to JetBrains AI to help you code faster. I’m going to walk you through some of these updates in this blog post. </p> <figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper"> <iframe loading="lazy" title="Code Faster with JetBrains AI in PyCharm!" width="500" height="281" src="https://www.youtube.com/embed/J7BXAv6-70g?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div></figure> <h2 class="wp-block-heading">Natural language inline AI prompt</h2> <p>You can now use JetBrains AI by typing straight into your editor in natural language without opening the AI Assistant tool window. If you use either IntelliJ IDEA or PyCharm, you might already be familiar with natural language AI prompts, but let me walk you through the process. </p> <p>If you’re typing in the gutter you can start typing your request straight into the editor, and then press <em>Tab</em>. Here’s an example of one such request:</p> <pre class="EnlighterJSRAW" data-enlighter-language="md" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">write a script to capture a date input from a user and print it out prefixed by a message stating that their birthday is on that date.</pre> <p>You can then iterate on the initial input by clicking on the purple block in the gutter or by pressing <em>⌘\ or Ctrl+\</em> and pressing <em>Enter</em>:</p> <pre class="EnlighterJSRAW" data-enlighter-language="md" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">add error handling so that when a birthday is in the future, we dont accept it </pre> <p>You can use <em>⌘\ or Ctrl+\</em> to keep iterating until you’re happy with the result. For example, we can use the prompt:</p> <pre class="EnlighterJSRAW" data-enlighter-language="md" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">print out the day of the week as well as their birthday date</pre> <p>And then: </p> <pre class="EnlighterJSRAW" data-enlighter-language="md" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">change the format of day_of_week to short</pre> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/code-iterate1.mp4"></video></figure> <p>This feature is available for Python, JavaScript, TypeScript, JSON, and YAML files.</p> <p>Let’s look at some more examples. We can get JetBrains AI Assistant to help us generate new code with a prompt like this:</p> <pre class="EnlighterJSRAW" data-enlighter-language="md" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Write code that lists the latest polls, shows poll details, handles voting, updates votes, and displays poll results, ensuring only published polls are accessible.</pre> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/add-code-polls1.mp4"></video></figure> <p>Or add some error handling to our code:</p> <pre class="EnlighterJSRAW" data-enlighter-language="md" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Add edge case handling to this code</pre> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/edge-case-handling.mp4"></video></figure> <p>Remember, context is everything. Where you start your natural language prompt is important, as PyCharm uses the placement of your caret to figure out the context. You don’t need to prefix your query with a ? or $ if you start typing in the gutter because the context is the file, but if your caret is indented, you’ll need to start your query with the ? or $ character so PyCharm knows you’re crafting a natural language query.</p> <p>In this example, we want to refactor existing code, so we need to prefix our query with the ? character:</p> <pre class="EnlighterJSRAW" data-enlighter-language="md" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">?create a dedicated function for printing the schedule and remove the code from here</pre> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/print-example.mp4"></video></figure> <p align="center"> <a class="jb-download-button" href="https://jb.gg/olx3f2" target="_blank" rel="noopener"> Try JetBrains AI for free </a> </p> <h2 class="wp-block-heading">Running code in the Python console</h2> <p>We know that JetBrains AI can generate code for you, but now you can run that code in the Python console without leaving the AI Assistant tool window by clicking the green run arrow.</p> <p>For example, let’s say you have the following prompt:</p> <pre class="EnlighterJSRAW" data-enlighter-language="md" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Create a python script that asks for a birthday date in standard format yyy-MM-dd then converts it and prints it back out in a written format such as 22nd January 1991 </pre> <p>You can now click the green run arrow on the top-right of the code snippet to run it in your Python console:</p> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/run-python-code.mp4"></video></figure> <h2 class="wp-block-heading">Even more features</h2> <p>In addition to the new functionality for natural language and code completion for PyCharm highlighted above, there are several other improvements to JetBrains AI. </p> <h3 class="wp-block-heading">Faster code completion</h3> <p>We have introduced a <a href="https://blog.jetbrains.com/blog/2024/10/22/introducing-mellum-jetbrains-new-llm-built-for-developers/">new model for faster cloud-based completion with AI Assistant</a> which is showing very promising results.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1200" height="675" src="https://blog.jetbrains.com/wp-content/uploads/2024/10/Post_Infographics_UPD.png" alt="" class="wp-image-520382"/></figure> <h3 class="wp-block-heading">Faster documentation</h3> <p>If documentation isn’t your thing, you can now hand off writing your Python docstrings to JetBrains AI. If you type either single or double quotes to enter a docstring and then press <em>Return</em>, you’ll see a prompt that says <em>Generate with AI Assistant</em>. Click that prompt and let JetBrains AI generate the documentation for you:</p> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/generate-docs.mp4"></video></figure> <h3 class="wp-block-heading">Help at your fingertips</h3> <p>We all need a little help now and again, and we can get JetBrains AI to help us here too. We’ve added a /docs prompt to the JetBrains AI tool window. This prompt will query the PyCharm documentation to save you from switching out of the context you’re working in!</p> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/getting-help.mp4"></video></figure> <h3 class="wp-block-heading">Ability to choose your LLM</h3> <p>For AI Chat, you can now select a different LLM from the drop-down menu in the chat window itself. There are lots of options for you to choose from:</p> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/choose-llm.mp4"></video></figure> <h3 class="wp-block-heading">More context in Jupyter notebooks</h3> <p>We’ve also improved how JetBrains AI works for data scientists. JetBrains AI now recognizes DataFrames and variables in your notebook. You can prefix your DataFrame or variable with # so that JetBrains AI considers it as part of the context. </p> <figure class="wp-block-video"><video controls src="https://blog.jetbrains.com/wp-content/uploads/2024/11/jupyter-hash-code-context.mp4"></video></figure> <h2 class="wp-block-heading">Summary</h2> <p>JetBrains AI is available inside PyCharm, right where you need it. This release brings many improvements, from writing in natural language inside the editor and running AI-generated Python snippets in the console to generating documentation. </p> <p>Remember, if you’re in the gutter, you can start typing in natural language and then press Tab to get AI Assistant to generate the code. If you’re inside a method or function, you need to prefix your natural language query with either ? or $. You can then iterate on the generated code as many times as you like as you build out your new functionality and explore further.</p> <p align="center"> <a class="jb-download-button" href="https://jb.gg/olx3f2" target="_blank" rel="noopener"> Try JetBrains AI for free</a> </p> ]]></content:encoded> </item> <item> <title>New Module Layout for sbt Projects</title> <link>https://blog.jetbrains.com/scala/2024/11/19/new-module-layout-for-sbt/</link> <dc:creator><![CDATA[Aleksandra Zdrojowa]]></dc:creator> <pubDate>Tue, 19 Nov 2024 15:00:19 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/cover_NewSbtMode.png</featuredImage> <category><![CDATA[intellij]]></category> <category><![CDATA[sbt]]></category> <category><![CDATA[scala]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=scala&p=527952</guid> <description><![CDATA[Try out the enhanced sbt integration with IntelliJ Scala Plugin 2024.3 We’re introducing a new mode that better represents the structure of sbt projects in IntelliJ IDEA by organizing main and test sources into separate modules. The improved layout resolves several issues with compilation and highlighting. It also allows using different compiler options for main […]]]></description> <content:encoded><![CDATA[ <h2 class="wp-block-heading"><strong>Try out the enhanced sbt integration with IntelliJ Scala Plugin 2024.3</strong></h2> <p>We’re introducing a new mode that better represents the structure of sbt projects in IntelliJ IDEA by organizing main and test sources into separate modules. The improved layout resolves several issues with compilation and highlighting. It also allows using different compiler options for main and test sources.</p> <p>We strongly encourage you to try out this new functionality and share your feedback! Enable it via <em>Settings | Build, Execution, Deployment | Build Tools | sbt</em> and select <em>Create separate modules for production and test sources</em>.</p> <h2 class="wp-block-heading"><strong>Technical background</strong></h2> <p>Each build tool has its own model to represent the project – this includes concepts of modules, dependencies, and much more.When the project is imported to IntelliJ IDEA, it is essential to translate this model into the IDE’s internal model, which may not perfectly align with the build tool’s structure.</p> <p>Improperly mapping a given build tool’s model to IntelliJ IDEA’s model can lead to issues, such as code compiling when it shouldn’t (or vice versa) and incorrect highlighting.</p> <p>A significant challenge when mapping the sbt model was the limited distinction between main and test sources. When managing dependencies between two modules, all sources from the dependent module were added to the parent module, making it impossible to include only the main sources. Another issue was configuring separate compiler options for main and test sources.</p> <p>To address these issues, a new approach has been developed for mapping the sbt model to IntelliJ IDEA – creating separate modules for main and test sources.</p> <p></p> <h2 class="wp-block-heading"><strong>How it works</strong></h2> <p>For each project declared in the sbt build, two additional modules are created: <code>main</code> and <code>test</code>. They contain the main and test sources, respectively.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1500" height="600" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/NewSbtModel-1.png" alt="" class="wp-image-527953"/></figure> <p><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe1vjburBdjqROkWXfuHmJ21DPT4bw0LRe74CIH9HO8CfIJbfbhXzmwEc8UNyD4HKAVKs9w3OTaOvyh4jm9IUBHaWGy7tur4fMQiVOfB0n1z39itQRPwxKbdYcwyogfgLJ4AajGgA?key=BBPvRXeK-pdBwAsikOnywGmF" style="width: 900px;"></p> <p>When the project is reloaded in the new mode, each run configuration that references a module should switch to the corresponding main or test module. This happens automatically when the new mode is activated. In very rare cases, it may not be possible to change the modules in the run configurations automatically. If this happens, a notification will appear, giving you the option to update the run configurations manually. If you miss the notification, you can still update the run configurations by explicitly using the <em>Update Run Configurations to the new module naming scheme</em> action.</p> <p><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXd-R3jX00DnEHp-5yW6qElLlVARgj86ilnMktZD1thpc00PWPGMceo1OE3cwRpbd77hn8HR2eTG1Ub30-1b2o5URKU5angI0kFQNFfULS8ItjCpLlYlEgB6vGhrnsNRKhw5eL2uzQ?key=BBPvRXeK-pdBwAsikOnywGmF" style="width: 900px;"></p> <p></p> <h2 class="wp-block-heading">Key improvements</h2> <p>These examples illustrate the most noticeable changes. However, enabling the new mode also allows for many other improvements, such as more accurate handling of transitive dependencies, support for <code>compile->test</code> dependencies, and better management of <code>-internal</code> configurations.</p> <p></p> <h3 class="wp-block-heading"><strong>Different compiler options for </strong>Compile <strong>and </strong>Test <strong>scopes</strong></h3> <p>sbt allows you to declare different compiler options in various configuration scopes. The new project model in IntelliJ IDEA now leverages this capability by recognizing compiler options declared in the <code>Test</code> scope, allowing you to configure different options for <code>Compile</code> and <code>Test</code> scopes in the IDE.</p> <p>For example, if you configure <code>scalacOptions</code> in an sbt project like this:<br><code>Test / scalacOptions += "-Ywarn-value-discard"</code><br>then warnings about discarded values will only be displayed in the test sources.</p> <p><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfJdEOAisDJrU8AEibKxxHLgPUXVI99CmZ28KZI9ewyetZxe9KIo9oFb039zBaPdffdvEKunv9RSI41TUIdbNN6S3B5sWJ-NFYckapbQ-W1NKf9eo5eU0O0rktZ6Xm72k_HDwZ5WHsnx2CZ0lLW3hg2Rkb4?key=BBPvRXeK-pdBwAsikOnywGmF" style="width: 900px;"></p> <p>If you configure the options in the Compile scope like this:<br><code>Compile / scalacOptions += "-Ywarn-value-discard"</code><br>then warnings can be displayed both in the main and test sources.</p> <p><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXek1xieW841SwTBcNCUlCN3ERqM36lYp9FiH3lwHNOQ08t_7qlcEMtxkkuD8xPiuXaChuzQzuJ2DLT7jOZ-SwhHE4fMaWWfLy4iauKCuKcyHs_uUT9ltTu-UgKSlSJrTyUmVAJ16Sj652mBA4Lrf5nIBvI?key=BBPvRXeK-pdBwAsikOnywGmF" style="width: 900px;"></p> <p></p> <h3 class="wp-block-heading">Compile scope project dependencies</h3> <p>Keeping main and test sources in separate modules allows for a more accurate representation of dependencies. This is particularly significant for classpath dependencies, which are always per-configuration in sbt.</p> <p>Let’s consider a very common dependency example:<br><code>core.dependsOn(foo)</code><br>which is always resolved to <br><code>core.dependsOn(foo %”compile->compile”)</code></p> <p>When separate modules for main and sources are created, this dependency resolves so that both <code>core.main</code> and <code>core.test</code> modules contain only the <code>core.foo.main</code> dependency. None of the core modules has <code>foo.test</code> in its dependencies, which is a proper sbt representation.</p> <p><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe2iYcTJClU2Rds-X5GGCwKIa-mTbmoOzbEDZCaT67LwzbaaKQeitU1vxcX7ThrEF3bEWXb5o0YeNrjvQ9xdFlvLRAwm0FGS9OcJpxOzwlG2y_seL2V__Y5LFyv6xOopPazbVbWi0LV97kJaVE0uquTj93p?key=BBPvRXeK-pdBwAsikOnywGmF" style="width: 900px;"></p> <p><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeZfdKyTuMXT92IXf4A_-ExS9JwRukW93YSNtk4mMs27gYPMQmkj282i7lkrPAcoFsAO1jOXATCVIc1NAv9uZTdPPT14xWKAxat3VWTLFVRolCjmXD89t_EBrUFiRe3-7iRobbtBF0Jbw1NciZ_NysynILS?key=BBPvRXeK-pdBwAsikOnywGmF" style="width: 900px;"></p> <p>It’s worth mentioning that in the old implementation, the core module included the entire <code>foo</code> module. This meant that <code>core</code> test sources had access to <code>foo</code> test sources.</p> <p></p> <h2 class="wp-block-heading"><strong>How to enable this feature</strong></h2> <p>As this feature is currently in Beta, it is not enabled by default.<strong> </strong>Enable it via <em>Settings | Build, Execution, Deployment | Build Tools | sbt</em> and select <em>Create separate modules for production and test sources</em>.</p> <p><img decoding="async" src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe6dE2erQZQY3MEoEg8JMP6t4Yo2543IVWdJdAB-rEx66pXoRJEXzMt95HFpXex5V0L2mxh1Stlr0GoSXnrjLBg533A11X7Ocrqr4S6K0OTdEVy7WIhpjo2sSz_C4Tjy6Nj_J27bgpXvbsfMnE6c8OFWL1W?key=BBPvRXeK-pdBwAsikOnywGmF" style="width: 900px;"></p> <p></p> <h2 class="wp-block-heading">Feedback</h2> <p>We need your feedback! If you encounter any bugs in this feature, please report them to our <a href="https://youtrack.jetbrains.com/issues/SCL" target="_blank" rel="noreferrer noopener">YouTrack</a>. If you have any questions, feel free to ask them on in our <a href="https://discord.com/channels/931170831139217469" target="_blank" rel="noreferrer noopener">Discord</a>.</p> <p>Happy developing!</p> <p>The <a href="https://plugins.jetbrains.com/plugin/1347-scala" target="_blank" rel="noreferrer noopener">IntelliJ Scala Plugin</a> team</p> ]]></content:encoded> </item> <item> <title>The MPS 2024.3 Early Access Program Is Open</title> <link>https://blog.jetbrains.com/mps/2024/11/the-mps-2024-1-eap-has-started-2-2/</link> <dc:creator><![CDATA[Vaclav Pech]]></dc:creator> <pubDate>Tue, 19 Nov 2024 13:07:36 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/Featured_Blog_1280x720-2x-9.png</featuredImage> <category><![CDATA[releases]]></category> <category><![CDATA[eap]]></category> <category><![CDATA[release]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=mps&p=528203</guid> <description><![CDATA[The first EAP build of MPS 2024.3 is now ready for you to download and try! DOWNLOAD MPS 2024.3 EAP The new version includes numerous fixes and improvements. Here are the two major ones that deserve special attention: Icon handling Icons and images that use a path relative to the module are no longer copied […]]]></description> <content:encoded><![CDATA[<p>The first EAP build of MPS 2024.3 is now ready for you to download and try!</p> <p align="center"><a class="jb-download-button" href="https://www.jetbrains.com/mps/nextversion/" target="_blank" rel="noopener">DOWNLOAD MPS 2024.3 EAP</a></p> <p>The new version includes numerous fixes and improvements. Here are the two major ones that deserve special attention:</p> <h2>Icon handling</h2> <p>Icons and images that use a path relative to the module are no longer copied during generation next to the places of their individual usage. Instead, they are copied to the distribution module once as image files and are available for use at this single location. This has two immediate benefits: avoiding the duplication of image files to save disk space and the ability to access the images both from the distribution and from the source module.</p> <h2>Constant icons</h2> <p>In addition to the existing <i>TextIcon</i> and <i>FileIcon</i> concepts, a new <i>ConstantFieldIcon</i> concept has become available. It allows an icon to be specified by reference to a concrete static field declaration holding an instance of <i>javax.swing.Icon</i>.</p> <h2>TextGen binary outcome</h2> <p>Inspired by the need for the improved handling of icon files, there is now a new mechanism to produce binary output during the TextGen process instead of text. The new API consists of a write operation that directly manipulates data as instances of <i>byte[]</i>.</p> <h2>Numerous bug fixes</h2> <p>You can find a full list of the issues we’ve fixed <a href="https://youtrack.jetbrains.com/issues/MPS?q=state:Resolved%20version:%20%7B2024.3%20EAP1%7D%20%20order%20by:%20Priority%20%20&_ga=2.231099997.350008667.1687951340-393819702.1681896790&_gl=1*183w1l3*_ga*MzkzODE5NzAyLjE2ODE4OTY3OTA.*_ga_9J976DJZ68*MTY4Nzk2NjcyOS4zMC4xLjE2ODc5Njc0MzYuNy4wLjA." target="_blank" rel="noopener">here</a>.</p> <p>This is only the first EAP release. We will keep adding more features and bigfixes to MPS 2024.3, so stay tuned!<br /> Your JetBrains MPS team</p> ]]></content:encoded> </item> <item> <title>From Code to Clarity With the Redesigned Structure Tool Window</title> <link>https://blog.jetbrains.com/idea/2024/11/from-code-to-clarity-with-the-redesigned-structure-tool-window/</link> <dc:creator><![CDATA[Siva Katamreddy]]></dc:creator> <pubDate>Tue, 19 Nov 2024 13:06:12 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/ij-featured_blog_1280x720_en-10.png</featuredImage> <category><![CDATA[idea]]></category> <category><![CDATA[java]]></category> <category><![CDATA[jetbrains-ai]]></category> <category><![CDATA[ai-assistant]]></category> <category><![CDATA[spring-boot]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=idea&p=524902</guid> <description><![CDATA[Developers usually spend more time reading existing code than writing new code. To understand the existing codebase of an application, developers spend a good amount of time looking at how various frameworks and libraries are configured and how different components interact with each other. While developing JetBrains AI Assistant, we enriched prompts with context extracted […]]]></description> <content:encoded><![CDATA[ <p>Developers usually spend more time reading existing code than writing new code. To understand the existing codebase of an application, developers spend a good amount of time looking at how various frameworks and libraries are configured and how different components interact with each other.</p> <p>While developing JetBrains AI Assistant, we enriched prompts with context extracted from file links and dependencies. This context proved valuable for both AI and human understanding.</p> <p>In this article, you will learn:</p> <ul> <li>How our R&D on AI Assistant led to redesigning the <em>Structure </em>tool window.</li> <li>How to use the new <em>Structure </em>tool window’s <em>Logical </em>view to explore and understand your existing codebase.</li> <li>How you can perform various context-relevant actions from the <em>Structure </em>tool window itself.</li> </ul> <h2 class="wp-block-heading">Background</h2> <p>AI assistants can produce disappointing results when asked to generate or explain code. This is because they can lack the rich context that developers are aware of. A project is not just code. It’s a complex interplay of components, both explicit like method calls, and implicit, defined by the framework being used. Understanding these intricate connections is crucial for accurate AI assistance.</p> <p>To get the best results from AI Assistant, we need to describe all this context to it. This same context would be invaluable for developers. In IntelliJ IDEA, the main code navigation tool is the <em>Project</em> tool window. It provides a code-level view of the project, including folders, packages, and files. Though familiar, the <em>Project</em> tool window doesn’t show links between code components. Developers have to figure those out themselves by looking for class usages for explicit links and reading the framework documentation for implicit ones.</p> <p>Unsurprisingly, IntelliJ IDEA knows a lot about project internals. While implementing support for a language or framework in the IDE, we, as developers, have to understand how a technology works under the hood. For example, if you open a file from the project implemented with the Spring Boot framework, you’ll see components like bean indicators, injection points, and web API endpoints.</p> <p>We recently introduced an internal API to implement <em>domain context providers</em> – code that can collect extended information about a project structure, used tech stack, etc. The first step was to provide better context for AI Assistant. We conducted R&D by seamlessly enriching prompts with the information from domain providers – this showed good results!</p> <p>The second step involved using this information to show the code structure from the framework perspective. In IntelliJ IDEA, the <em>Structure</em> tool window presents the structure of a selected file. We decided to enhance this window and add a <em><a href="https://www.jetbrains.com/help/idea/viewing-structure-of-a-source-file.html#logical-structure" data-type="link" data-id="https://www.jetbrains.com/help/idea/viewing-structure-of-a-source-file.html#logical-structure" target="_blank" rel="noopener">Logical</a></em> view, which illustrates the file structure from the framework point of view. This means that you can now see how a selected piece of code, such as a file or class, is connected to other parts of the application. This context is sometimes more valuable than the code itself because it helps you understand how an application works.</p> <h2 class="wp-block-heading"><em>Structure </em>tool window redesign</h2> <p>Let’s explore a Spring Boot application to learn how the new <em>Structure </em>tool window provides better insights into your application by providing a logical structure of the components, indicating how they all work together.</p> <p>The entry point of any Spring Boot application is the main application class annotated with <code>@SpringBootApplication</code>. The class code’s physical structure is simple:</p> <pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@SpringBootApplication public class BlogApplication { public static void main(String[] args) { SpringApplication.run(BlogApplication.class, args); } }</pre> <div class="wp-block-image"> <figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="440" height="145" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/spring-boot-app-physical.png" alt="" class="wp-image-524982"/></figure></div> <p>The magic of Spring Boot is hidden in bean configurations – classes that instantiate required services based on various conditions and put them into the Spring context. Now, we can see it!</p> <div class="wp-block-image"> <figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="597" height="469" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/spring-boot-app-logical.png" alt="" class="wp-image-524971"/></figure></div> <p>Domain context providers know which configurations are scanned and which beans are instantiated by bean configuration – it’s all revealed in the structure.</p> <p>Now, let’s take a look at how the <em>Structure </em>tool window shows the logical view of a Spring Boot REST controller.</p> <div class="wp-block-image"> <figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="552" height="340" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/image-10.png" alt="" class="wp-image-524925"/></figure></div> <p>The <em>Structure </em>tool window displays the autowired Spring beans in the <code>Autowires</code> node and the API endpoints defined in the controller class. When you click on any API endpoint, you will be taken to that method in the editor. You can also click on the API gutter icon to invoke that API endpoint in the HTTP Client.</p> <p>The Spring Framework provides event publishing and consuming capabilities using <code>ApplicationEventPublisher</code>. If the selected Spring bean publishes events using <code>ApplicationEventPublisher</code>, you can see these details under the <code>Publishers</code> node.</p> <div class="wp-block-image"> <figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="579" height="312" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/image-11.png" alt="" class="wp-image-524936"/></figure></div> <p>Similarly, if the Spring bean implements event listeners using <code>@EventListener</code>, the listeners’ details are shown under the <code>Listeners</code><strong> </strong>node.</p> <div class="wp-block-image"> <figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="585" height="277" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/image-12.png" alt="" class="wp-image-524947"/></figure></div> <p>Let’s take another example: JPA entities.</p> <p>The <em>Structure</em> tool window also provides a <em>Logical </em>view of JPA entities by providing a lot of context, such as the column mappings, relationship with other entities, Spring Data JPA repositories associated with the entity, and related DTOs and projections:</p> <div class="wp-block-image"> <figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="555" height="474" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/image-13.png" alt="" class="wp-image-524958"/></figure></div> <p>If you select the Entity node, you can see the DDL gutter icon which you can use to generate an SQL script to create the table.</p> <p>Similarly, IntelliJ IDEA provides a <em>Logical </em>view for other Spring components like MVC controllers, services, repositories, and configuration classes.</p> <div class="wp-block-image"> <figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="1920" height="1080" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/structure-tool-window.gif" alt="" class="wp-image-524996"/></figure></div> <h2 class="wp-block-heading">Conclusion</h2> <p>An application’s complex structure consists of various parts, including code, dependencies, build processes, and deployment scripts. A solid grasp of the connections between these components is crucial for a comprehensive understanding of the application’s architecture and functionality. </p> <p>By introducing domain context providers, we can explain the code structure from another point of view, revealing hidden framework-specific connections between various components. This can be useful for AI Assistant, so its answers could be improved, as well as for developers to help them understand the code better.</p> <p>The redesigned <em>Structure </em>tool window’s <em>Logical</em> view allows you to see the application structure and navigate through linked components. The context-specific actions associated with the selected component make it easy to perform various tasks right from the <em>Structure </em>tool window itself.</p> <p>Currently, the IDE supports Jakarta EE and Spring, and we plan to expand this support to other technologies like frameworks, build tools, and Docker configuration files.</p> <p>You can find the official documentation for <em>Logical</em> <em>structure</em> <a href="https://www.jetbrains.com/help/idea/viewing-structure-of-a-source-file.html#logical-structure" data-type="link" data-id="https://www.jetbrains.com/help/idea/viewing-structure-of-a-source-file.html#logical-structure" target="_blank" rel="noopener">here</a> .</p> <p>The redesigned <em>Structure </em>tool window is available in IntelliJ IDEA Ultimate 2024.3, and the context-relevant actions support will be available from version 2024.3.1. You can install the latest version of the IDE from the <a href="https://www.jetbrains.com/toolbox-app/" target="_blank" rel="noopener">JetBrains Toolbox App</a>, or you can download and install it from our website.</p> <p align="center"><a class="jb-download-button" href="https://www.jetbrains.com/idea/" target="_blank" rel="noopener" data-test="blog-article-cta">Download IntelliJ IDEA</a></p> ]]></content:encoded> </item> <item> <title>Busy Plugin Developers Newsletter – Q3 2024</title> <link>https://blog.jetbrains.com/platform/2024/11/busy-plugin-developers-newsletter-q3-2024/</link> <dc:creator><![CDATA[Elena Kerpeleva]]></dc:creator> <pubDate>Mon, 18 Nov 2024 20:39:43 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/mp-featured_blog_1280x720_en.png</featuredImage> <category><![CDATA[marketplace]]></category> <category><![CDATA[news]]></category> <category><![CDATA[busy-plugin-developers]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=platform&p=527916</guid> <description><![CDATA[⭐️ Community highlights JetBrains Plugin Developer Conf 2024: Kicking off our first event On November 7, we hosted the first-ever JetBrains Plugin Developer Conf, a virtual event dedicated entirely to plugin development for JetBrains products. The conference brought together JetBrains experts and plugin developers to explore a wide range of topics, including developing and launching […]]]></description> <content:encoded><![CDATA[ <h2 class="wp-block-heading">⭐️ Community highlights</h2> <h3 class="wp-block-heading"><strong>JetBrains Plugin Developer Conf 2024: Kicking off our first event</strong></h3> <p>On November 7, we hosted the first-ever <a href="https://lp.jetbrains.com/plugin-dev-conf-2024/" data-type="link" data-id="https://lp.jetbrains.com/plugin-dev-conf-2024/" target="_blank" rel="noopener">JetBrains Plugin Developer Conf</a>, a virtual event dedicated entirely to plugin development for JetBrains products.</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1280" height="720" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Blog_1280x720-1.png" alt="" class="wp-image-528521"/></figure> <p>The conference brought together JetBrains experts and plugin developers to explore a wide range of topics, including developing and launching plugins on JetBrains Marketplace, plugin localization, handling user feedback, plugin testing, building collaborative plugins, and more. Attendees also got a glimpse into our future plans for Marketplace and the latest tooling updates.</p> <p>Missed the event? You can watch the recording <a href="https://www.youtube.com/watch?v=nsEGDXvnsa4" data-type="link" data-id="https://www.youtube.com/watch?v=nsEGDXvnsa4" target="_blank" rel="noopener">here</a>.</p> <h2 class="wp-block-heading">⭐️ Marketplace updates</h2> <h3 class="wp-block-heading">Special offers are now displayed on the Pricing Tab</h3> <p>Paid plugin authors can now display discounts on the Pricing Tab, with the previous price crossed out. To set up a special offer, reach out to the JetBrains Marketplace Support team. Learn more in our <a href="https://plugins.jetbrains.com/docs/marketplace/special-offers.html" target="_blank" rel="noopener">documentation. </a></p> <span id="more-527916"></span> <figure class="wp-block-image size-full is-resized"><img decoding="async" loading="lazy" width="1667" height="903" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/special-offers.png" alt="" class="wp-image-527917" style="aspect-ratio:1.8460686600221483;width:840px;height:auto"/></figure> <h3 class="wp-block-heading"><strong>Sales report update</strong></h3> <p>We’ve made some improvements to our sales report. You can now filter reports by month, and the table includes detailed information about purchased licenses. Additionally, the full report can be downloaded as a .csv file. </p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="1920" height="1080" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/Updated-Sales-Report_forX.gif" alt="" class="wp-image-527928"/></figure> <h3 class="wp-block-heading"><strong>More new UI Icons for your plugins</strong></h3> <p>We’ve added over 1,000 new UI icons to the IntelliJ Platform Icons library. These icons are tailored to the new UI and come with Apache 2.0 licensing. You can also use our Figma library to design your own custom icons. Get all the details in this <a href="https://blog.jetbrains.com/platform/2024/08/more-new-ui-icons-for-your-plugins/" data-type="link" data-id="https://blog.jetbrains.com/platform/2024/08/more-new-ui-icons-for-your-plugins/">blog post</a>. </p> <h3 class="wp-block-heading"><strong>Migrating your IntelliJ IDEA Kotlin plugin to K2 Mode</strong></h3> <p>If your plugin code depends on the Kotlin K1 plugin API, this news is for you. Starting from IntelliJ 2024.2.1, you need to migrate to the Kotlin K2 mode. Otherwise, your plugin might not work properly when K2 mode is enabled. Learn more about how to migrate in this <a href="https://blog.jetbrains.com/platform/2024/09/migrating-your-kotlin-plugin-to-k2-mode/" data-type="link" data-id="https://blog.jetbrains.com/platform/2024/09/migrating-your-kotlin-plugin-to-k2-mode/">blog post</a>.</p> <h2 class="wp-block-heading">⭐️ Plugin development tooling updates</h2> <h3 class="wp-block-heading"><strong>IntelliJ Platform Plugin Template 2.0.2</strong></h3> <p>The IntelliJ Platform Plugin Template is a repository that streamlines the initial stages of plugin development for IntelliJ-based IDEs. The latest update upgrades the Gradle Wrapper to 8.10.2, sets the platformVersion to 2023.3.8, and updates key dependencies. Check out the <a href="https://github.com/JetBrains/intellij-platform-plugin-template/releases" data-type="link" data-id="https://github.com/JetBrains/intellij-platform-plugin-template/releases" target="_blank" rel="noopener">release notes</a> for more details. </p> <h3 class="wp-block-heading"><strong>IntelliJ Plugin Verifier 1.379</strong></h3> <p>Plugin Verifier Version 1.379 adds the ability to ignore restrictions on the internal <code>com.intellij.languageBundle</code> extension point, improved handling for malformed annotation descriptors with obfuscation, and support for composite action names with namespaces in TeamCity Actions. This update also removes duplicate vendor checks for JetBrains plugins, unifies plugin problem classification, and fixes an issue with empty dotnet plugin names. Check out the <a href="https://github.com/JetBrains/intellij-plugin-verifier/releases/tag/1.379" target="_blank" rel="noopener">changelog</a> for more details.</p> <h3 class="wp-block-heading"><strong>IntelliJ Platform Gradle Plugin 2.0 is out</strong></h3> <p>Version 2.0 of the IntelliJ Platform Gradle Plugin is now available. This updated plugin for the Gradle build system simplifies the configuration of environments for building, testing, verifying, and publishing plugins for IntelliJ-based IDEs. Find all of the details <a href="https://blog.jetbrains.com/platform/2024/07/intellij-platform-gradle-plugin-2-0/">here. </a></p> <h2 class="wp-block-heading">⭐️ Useful resources</h2> <h3 class="wp-block-heading"><strong>Threading Model and Background Processes</strong></h3> <p>The revamped <a href="https://plugins.jetbrains.com/docs/intellij/threading-model.html" target="_blank" rel="noopener">Threading Model</a> page provides updated guidance on managing concurrency in the IntelliJ Platform, detailing UI thread restrictions, background tasks, and thread safety to help developers build responsive, stable plugins. </p> <p>The new <a href="https://plugins.jetbrains.com/docs/intellij/background-processes.html" target="_blank" rel="noopener">Background Processes</a> page complements this with best practices for handling asynchronous tasks, using progress indicators, and creating cancelable tasks for enhanced user experience and performance.</p> <p><strong>Workspace Model</strong></p> <p>The <a href="https://plugins.jetbrains.com/docs/intellij/workspace-model.html" target="_blank" rel="noopener">Workspace Model</a> article introduces plugin developers to the Workspace Model in the IntelliJ Platform, highlighting its architecture, data handling capabilities, and interaction with the<a href="https://plugins.jetbrains.com/docs/intellij/project-model.html" target="_blank" rel="noopener"> Project Model</a>. It explains how to use the Workspace Model to efficiently store, manage, and access project-related data.</p> ]]></content:encoded> </item> <item> <title>Let’s meet at Slush 2024 in Helsinki!</title> <link>https://blog.jetbrains.com/blog/2024/11/18/let-s-meet-at-slush-2024-in-helsinki/</link> <dc:creator><![CDATA[Alexandra Charikova]]></dc:creator> <pubDate>Mon, 18 Nov 2024 18:26:29 +0000</pubDate> <featuredImage>https://blog.jetbrains.com/wp-content/uploads/2024/11/jb-social_share_blog_1280x720_en.png</featuredImage> <category><![CDATA[events]]></category> <category><![CDATA[startup-offer]]></category> <category><![CDATA[startups]]></category> <guid isPermaLink="false">https://blog.jetbrains.com/?post_type=blog&p=528503</guid> <description><![CDATA[Meet with our JetBrains for Startups team at Slush 2024 in Helsinki on November 20–21! This November, our JetBrains team is returning for the third year in a row to the most founder-focused event on Earth. Join us at booth 7A2 to discuss how our tools can accelerate your startup’s growth, win exclusive swag, or […]]]></description> <content:encoded><![CDATA[ <p>Meet with our JetBrains for Startups team at Slush 2024 in Helsinki on November 20–21!</p> <p>This November, our JetBrains team is returning for the third year in a row to the most founder-focused event on Earth. Join us at booth 7A2 to discuss how our tools can accelerate your startup’s growth, win exclusive swag, or simply drop by to say hello!</p> <p>Our team will be there to talk about AI, scaling startups, and the future of development. In addition, we’ll be showcasing our latest AI-powered tools, including IDEs, AI Assistant, and YouTrack. You can also catch a glimpse of the new tools, special partner offers, and exclusive resources that have been added to our JetBrains Startup Program. Whether you are building your first MVP, scaling up, or refining your product, our tools can support you in the process.</p> <p>You can also learn more about our Partner Program for incubators, accelerators, and investors – a unique opportunity to bring JetBrains tools to your portfolio companies. To meet with us, book a slot via the <a href="https://platform.slush.org/companies/0bb312c5-aeeb-47df-928a-1a26fc1bdcc4" target="_blank" rel="noopener">Slush Platform</a>, reach out at <a href="mailto:startups@jetbrains.com">startups@jetbrains.com</a>, or simply stop by our booth.</p> <p>Don’t miss our special activities, including a Wheel of Fortune with special prizes to be won!</p> <figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="2560" height="1440" src="https://blog.jetbrains.com/wp-content/uploads/2024/11/jb-social_share_blog_1280x720_en.png" alt="" class="wp-image-528504"/></figure> <p><strong>Where to find us:</strong></p> <ul> <li><strong>Hall:</strong> 7 | <strong>Booth:</strong> 7A2, near the Builder Stage and Mentoring Area</li> <li><strong>Venue:</strong> Messukeskus Helsinki</li> </ul> <p></p> <p>Learn more about our programs for startups:</p> <p><a href="https://www.jetbrains.com/store/startups/" target="_blank" rel="noopener">JetBrains Startup Program</a></p> <p><a href="https://www.jetbrains.com/company/incubators/apply/" target="_blank" rel="noopener">JetBrains Partner Program for incubators, accelerators and investors</a></p> <p>We look forward to connecting with you at Slush 2024 and exploring how JetBrains can help bring your ideas to life. See you there!</p> ]]></content:encoded> </item> </channel> </rss>