<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: JetBrains TeamCity</title>
    <description>The latest articles on Forem by JetBrains TeamCity (@teamcity).</description>
    <link>https://forem.com/teamcity</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F856583%2F42f3f23f-95a2-4aa1-bb05-84c672fb170e.png</url>
      <title>Forem: JetBrains TeamCity</title>
      <link>https://forem.com/teamcity</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/teamcity"/>
    <language>en</language>
    <item>
      <title>How We Taught AI Agents to See the Bigger Picture</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Wed, 25 Mar 2026 20:36:03 +0000</pubDate>
      <link>https://forem.com/teamcity/how-we-taught-ai-agents-to-see-the-bigger-picture-342f</link>
      <guid>https://forem.com/teamcity/how-we-taught-ai-agents-to-see-the-bigger-picture-342f</guid>
      <description>&lt;h2&gt;The problem: Good code is not always accepted code&lt;/h2&gt;

&lt;p&gt;AI agents can write working code. They can make changes that compile, pass tests, and finish tasks. And yet the pull request might still be rejected.&lt;/p&gt;

&lt;p&gt;That happens because every codebase has its own internal logic. Teams have naming conventions, preferred APIs, and patterns they trust. Some of those rules are documented, but many are not.&lt;/p&gt;

&lt;p&gt;Pavel Sher (Technical Lead for TeamCity) has reviewed thousands of commits over the years. That experience helps him spot when a change technically works but still does not fit the project. He can suggest better naming, a more appropriate approach, or a solution that stays consistent with the rest of the codebase.&lt;/p&gt;

&lt;p&gt;This led us to a practical question: how can we help AI agents see the bigger picture, too?&lt;/p&gt;

&lt;h2&gt;The trap: Agents learn from what they see&lt;/h2&gt;

&lt;p&gt;When you ask an AI agent to write code, it usually looks through the codebase for examples. It tries to infer conventions from existing code and follow the patterns it finds.&lt;/p&gt;

&lt;p&gt;That sounds reasonable, but it becomes a problem in large, long-lived projects.&lt;/p&gt;

&lt;p&gt;If an agent sees the same pattern repeated 100 times, it will often assume that this is the right way to do things. It repeats the pattern because it is trying to stay consistent with the project.&lt;/p&gt;

&lt;p&gt;But in legacy codebases, the most common pattern is not always the one the team wants to keep using.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage-23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage-23.png" alt="" width="800" height="436"&gt;&lt;/a&gt;&lt;em&gt;Image generated with the help of AI&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An agent cannot tell whether those 100 examples represent the current standard or an old approach the team is gradually replacing. It sees frequency and mistakes it for correctness.&lt;/p&gt;

&lt;p&gt;That is the core issue. Without guidance, agents tend to inherit legacy approaches simply because those approaches appear more often.&lt;/p&gt;

&lt;h2&gt;The experiment: Refactoring legacy database code&lt;/h2&gt;

&lt;p&gt;Like many mature products, TeamCity has a fair amount of legacy code. In one of our experiments, we wanted to migrate several classes from an old database API to a newer one.&lt;/p&gt;

&lt;p&gt;This was not a mechanical refactoring. The new API did not map directly to the old one, so a simple method-by-method replacement was not enough. The migration required understanding how to reshape the code, which patterns to use, and and how to handle special edge-cases.&lt;/p&gt;

&lt;p&gt;We asked an AI agent to perform the migration.&lt;/p&gt;

&lt;p&gt;The result looked good at first. The code worked, tests passed, and the new API was in place. But during review, Pavel noticed a major issue.&lt;/p&gt;

&lt;p&gt;The agent had updated the API calls, but everything around them still followed the old design. It reused legacy error handling, legacy data flow, and legacy structure because that was what it found in the surrounding code.&lt;/p&gt;

&lt;p&gt;So the result was technically correct, but conceptually inconsistent: new API calls implemented using the old design.&lt;/p&gt;

&lt;h2&gt;First step: Show examples of accepted work&lt;/h2&gt;

&lt;p&gt;Our first improvement was simple. Instead of relying only on the current codebase, we gave the agent examples of migrations that had already been reviewed and accepted.&lt;/p&gt;

&lt;p&gt;In effect, the instruction became: “Here is how we migrated Class A, now apply the same approach to Class B.”&lt;/p&gt;

&lt;p&gt;That worked noticeably better. The agent no longer focused only on replacing API calls. It started following the direction of the migration more accurately, and the resulting code fit the project better.&lt;/p&gt;

&lt;p&gt;However, this approach did not scale well. We could not keep feeding accepted examples to the agent one by one for every new task.&lt;/p&gt;

&lt;h2&gt;Second step: Turn accepted changes into explicit rules&lt;/h2&gt;

&lt;p&gt;We continued by looking at accepted migration commits and studying what they had in common. From those commits, we extracted patterns the team had already approved and turned them into a practical set of rules.&lt;/p&gt;

&lt;p&gt;The document was straightforward and simply told the agents: “When migrating from API X to API Y, follow these patterns, avoid these mistakes, and use these naming conventions.”&lt;/p&gt;

&lt;p&gt;Using this document led to further improvements in the quality of changes. Merge requests began to pass review with far fewer comments.&lt;/p&gt;

&lt;h2&gt;The key insight: History is documentation&lt;/h2&gt;

&lt;p&gt;This is where we came to a realization.&lt;/p&gt;

&lt;p&gt;We had been writing rules by hand, but the underlying knowledge already existed in the repository. Accepted commits showed what good changes looked like. Review comments reflected the concerns of the team. The project history already contained what we were trying to teach to AI.&lt;/p&gt;

&lt;p&gt;So instead of documenting everything manually, we had another idea: we’d extract that knowledge directly from Git history.&lt;/p&gt;

&lt;h2&gt;CommitAtlas: Learning from repository history&lt;/h2&gt;

&lt;p&gt;That idea served as the basis for &lt;strong&gt;CommitAtlas&lt;/strong&gt;, an internal tool that reads Git history and answers questions about how things should be done in the project.&lt;/p&gt;

&lt;p&gt;At a high level, it works like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import commits into a database&lt;/li&gt;



&lt;li&gt;Use an LLM to describe each record based on the commit message and patch&lt;/li&gt;



&lt;li&gt;Answer questions such as "How do I migrate from API A to API B?" or "What naming convention do we use for services?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike ordinary code search, CommitAtlas does not simply show what appears most often in the repository. It analyzes recent accepted changes to identify which patterns the project is actively adopting. &lt;/p&gt;

&lt;p&gt;For example, it may recognize that a newer API is replacing an older one, even if the older API still appears more frequently in the codebase.&lt;/p&gt;

&lt;h2&gt;Documentation on demand for AI agents&lt;/h2&gt;

&lt;p&gt;Now, before writing code, our AI agents can query CommitAtlas and get a short, task-specific guide assembled from real project history.&lt;/p&gt;

&lt;p&gt;That guide can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recommended implementation patterns&lt;/li&gt;



&lt;li&gt;Code examples from accepted commits&lt;/li&gt;



&lt;li&gt;Links to the source commits&lt;/li&gt;



&lt;li&gt;Naming and style guidance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, this gives the agent something close to what an experienced teammate would provide: context before implementation.&lt;/p&gt;

&lt;h2&gt;What we saw in practice&lt;/h2&gt;

&lt;p&gt;Our original hypothesis turned out to be correct. Git history contains a large part of the knowledge that makes code not just functional, but acceptable to the team.&lt;/p&gt;

&lt;p&gt;When agents use CommitAtlas, they tend to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand project context faster&lt;/li&gt;



&lt;li&gt;Produce code that follows local conventions more closely&lt;/li&gt;



&lt;li&gt;Get fewer pull request rejections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The knowledge base also improves over time. Each new commit adds more real examples of how the codebase evolves, and human feedback helps refine the generated guidance.&lt;/p&gt;

&lt;h2&gt;Why this matters for legacy projects&lt;/h2&gt;

&lt;p&gt;If your project has been around for years, your repository contains a lot of institutional knowledge.&lt;/p&gt;

&lt;p&gt;Commits, reviews, and accepted refactorings show how the codebase has evolved and what the team has learned along the way. Traditional documentation rarely keeps pace with that kind of change, especially in large systems. But repository history does keep pace, because it records what was actually changed and what was actually accepted.&lt;/p&gt;

&lt;p&gt;For teams working with AI agents, this matters a lot. It is not enough to give the agent access to the code. You also need to give it access to the context that explains which patterns still belong to the project and which ones are being left behind.&lt;/p&gt;

&lt;p&gt;That context is what helps agents produce code that fits naturally into an existing codebase and meets the standards experienced reviewers expect.&lt;/p&gt;

&lt;h2&gt;A practical takeaway&lt;/h2&gt;

&lt;p&gt;Many teams are starting to experiment with AI coding agents. In practice, the biggest challenge is not getting the agent to write code that compiles. The real challenge is getting it to write code that fits the project.&lt;/p&gt;

&lt;p&gt;Every repository contains a large amount of implicit knowledge. Commit history, refactorings, and accepted pull requests all reflect decisions the team has made over time. Together they show which patterns are encouraged, which ones are being phased out, and how the codebase is evolving.&lt;/p&gt;

&lt;p&gt;If AI agents can access and interpret that history, they can start making decisions that better match the intent of the project instead of simply copying what appears most often in the code.&lt;/p&gt;

&lt;p&gt;For teams working with large or long-lived codebases, repository history may be one of the most useful sources of guidance you can provide to an AI agent. It captures how the system actually evolved and what changes were accepted along the way.&lt;/p&gt;

&lt;p&gt;Helping agents learn from that history can make the difference between code that technically works and code that genuinely belongs in the project.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>cicd</category>
      <category>teamcity</category>
    </item>
    <item>
      <title>$ teamcity From the Command Line</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Thu, 19 Mar 2026 10:01:27 +0000</pubDate>
      <link>https://forem.com/teamcity/-teamcity-from-the-command-line-j45</link>
      <guid>https://forem.com/teamcity/-teamcity-from-the-command-line-j45</guid>
      <description>&lt;p&gt;&lt;em&gt;Start builds, tail logs, and manage agents and queues – without switching windows.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Whether you are debugging a failed build, managing build agents, or scripting your deployment pipeline (or your AI coding agent is doing so) – there are times when opening a browser is one step too many.&lt;/p&gt;

&lt;p&gt;TeamCity CLI is a lightweight, open-source tool that puts TeamCity at your fingertips. &lt;/p&gt;

&lt;p&gt;A CLI for TeamCity has been a long-standing request from the community. Here’s how it works and what you can use it for.&lt;/p&gt;

&lt;p&gt;TeamCity CLI includes over 60 commands, and for anything it doesn't wrap yet, &lt;code&gt;teamcity api&lt;/code&gt; gives you direct access to the full TeamCity REST API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source code (Apache 2.0):&lt;/strong&gt; &lt;a href="https://github.com/JetBrains/teamcity-cli" rel="noopener noreferrer"&gt;https://github.com/JetBrains/teamcity-cli&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Getting started&lt;/h2&gt;

&lt;p&gt;Install and authenticate in seconds:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# macOS / Linux
brew install jetbrains/utils/teamcity

# via a bash script
curl -fsSL https://jb.gg/tc/install | bash

# Windows
winget install JetBrains.tc

# via a powershell script
irm https://jb.gg/tc/install.ps1 | iex

# Connect to your server
teamcity auth login https://example.teamcity.com/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's all! Now let’s see it in action.&lt;/p&gt;

&lt;h2&gt;Investigating a failed build&lt;/h2&gt;

&lt;p&gt;Let’s say something breaks. Here’s how to go from wondering what happened to having it fixed without switching windows.&lt;/p&gt;

&lt;h3&gt;See what's happening&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;teamcity run list --all&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage3.gif" alt="" width="720" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build 1389 failed. Here’s how we can drill down:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;teamcity run view 1389&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Need to jump to the TeamCity UI instead? Add &lt;code&gt;--web&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Find the root cause&lt;/h3&gt;

&lt;p&gt;You don't need to scroll through the entire log. Show only the failed step, then the failed tests:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;teamcity run log 1389 --failed&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fgif-1_see-whats-happening-1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fgif-1_see-whats-happening-1.gif" alt="" width="720" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only one test failed, so you know exactly what to fix.&lt;/p&gt;

&lt;h3&gt;Fix and re-trigger&lt;/h3&gt;

&lt;p&gt;After you push the fix, restart and watch it in real time:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;teamcity run restart 1389
teamcity run watch 1408 --logs&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage1.gif" alt="" width="560" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see all the updates happening live in your terminal – build state changes, step progress, and streaming log output.&lt;/p&gt;

&lt;h3&gt;Test before you push&lt;/h3&gt;

&lt;p&gt;Want to validate your changes with CI before committing to a push? Run &lt;a href="https://www.jetbrains.com/help/teamcity/personal-build.html" rel="noopener noreferrer"&gt;a personal build&lt;/a&gt; with your local changes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;teamcity run start Sandbox_Test --local-changes&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;TeamCity runs the build with your uncommitted work applied as a patch – no branch, no force-push, no noise in the repo.&lt;/p&gt;

&lt;h2&gt;Remote agent access&lt;/h2&gt;

&lt;p&gt;You can open an interactive shell session on any build agent – or execute commands remotely:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;teamcity agent list
teamcity agent term 813&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage2.gif" alt="" width="760" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No SSH keys to manage, no VPN to connect – if your TeamCity server can reach the agent, so can you. &lt;/p&gt;

&lt;p&gt;Need to just run a quick command? Here’s how:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;teamcity agent exec 813 "docker ps -a"&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Built for scripting&lt;/h2&gt;

&lt;p&gt;teamcity covers queues, agents, artifacts, and project configuration – the commands look exactly as you’d expect:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;teamcity queue list                                          # what's queued
teamcity queue top 461                                       # move a build to the front
teamcity queue approve 462                                   # approve a waiting build

teamcity agent list                                          # all agents with status
teamcity agent disable "Linux Agent 03" --comment "Maint"    # take one offline

teamcity run artifacts 453                                   # browse artifacts
teamcity run download 453 "reports/**/*.html" --output ./out # grab what you need

# Restart all failed builds on main
teamcity run list --failed --branch main --plain=id | xargs -I{} tc run restart {}

# Structured data for dashboards or scripts
teamcity run list --failed --json=id,status,buildType.name

# Hit any REST API endpoint directly
teamcity api /app/rest/server
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Every list command supports &lt;code&gt;--json&lt;/code&gt; with field selection and &lt;code&gt;--plain&lt;/code&gt; for tab-delimited text – making &lt;code&gt;teamcity&lt;/code&gt; a building block for automation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;teamcity api&lt;/code&gt; is the escape hatch – anything the CLI doesn't wrap yet, you can call directly.&lt;/p&gt;

&lt;h2&gt;Compatible with AI coding agents&lt;/h2&gt;

&lt;p&gt;TeamCity CLI ships with an &lt;a href="https://agentskills.io" rel="noopener noreferrer"&gt;Agent Skill&lt;/a&gt; that teaches AI coding assistants how to use the tool. Your AI agent can then check the build status, investigate failures, download artifacts, and manage your pipeline on your behalf.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Users should limit the token rights granted to the agent, be aware of security implications, and always check the actions the agent intends to execute.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2026%2F03%2Fimage5.gif" alt="" width="720" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;What's next&lt;/h2&gt;

&lt;p&gt;TeamCity CLI is open-source under Apache 2.0. There's more we want to build – for example, pipeline visualization, richer TUI interfaces, and deeper integration with version control workflows. Your feedback will shape what comes next.&lt;/p&gt;

&lt;h2&gt;Try it&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;brew install jetbrains/utils/teamcity       # macOS
winget install JetBrains.TeamCityCLI        # Windows
curl -fsSL https://jb.gg/tc/install | bash  # Linux/macOS setup script
irm https://jb.gg/tc/install.ps1 | iex      # Windows setup script&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Source code and docs:&lt;/strong&gt; &lt;a href="https://github.com/JetBrains/teamcity-cli" rel="noopener noreferrer"&gt;github.com/JetBrains/teamcity-cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Report issues or request features:&lt;/strong&gt;&lt;a href="https://github.com/JetBrains/teamcity-cli/issues" rel="noopener noreferrer"&gt; GitHub Issues&lt;/a&gt;&lt;/p&gt;

</description>
      <category>teamcity</category>
      <category>cli</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Case Study: How Junie Uses TeamCity to Evaluate Coding Agents</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Tue, 03 Jun 2025 15:34:14 +0000</pubDate>
      <link>https://forem.com/teamcity/case-study-how-junie-uses-teamcity-to-evaluate-coding-agents-b54</link>
      <guid>https://forem.com/teamcity/case-study-how-junie-uses-teamcity-to-evaluate-coding-agents-b54</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/junie/" rel="noopener noreferrer"&gt;Junie&lt;/a&gt; is an intelligent coding agent developed by JetBrains. It automates the full development loop: reading project files, editing code, running tests, and applying fixes, going far beyond simple code generation.&lt;/p&gt;

&lt;p&gt;Similar to how developers use tools like ChatGPT to solve coding problems, Junie takes it a step further by automating the entire process.&lt;/p&gt;

&lt;p&gt;As the agent’s architecture evolved, the team needed a secure, robust way to measure progress. They wanted to build a scalable, reproducible evaluation pipeline that would be able to track changes across hundreds of tasks.&lt;/p&gt;

&lt;p&gt;That’s where &lt;a href="https://jetbrains.com/teamcity" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt; came in. Junie’s development team uses TeamCity to orchestrate large-scale evaluations, coordinate Dockerized environments, and track important metrics that guide Junie’s improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  The challenge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Validating agent improvements at scale
&lt;/h3&gt;

&lt;p&gt;As Junie’s agents became more capable, with new commands and smarter decision-making, every change needed to be tested for real impact. Evaluation had to be systematic, repeatable, and grounded in data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did it get better or not?’ is a very poor way to evaluate. If I just try three examples from memory and see if it got better, that leads nowhere. That’s not how you achieve stable, consistent improvements. You need a benchmark with a large and diverse enough set of tasks to actually measure anything. - &lt;em&gt;Danila Savenkov, Team Lead, JetBrains Junie&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The team identified five core requirements for this process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scale&lt;/strong&gt;: Evaluations had to cover at least 100 tasks per run to minimize statistical noise. Running fewer tasks made it hard to draw meaningful conclusions​.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parallel execution&lt;/strong&gt;: Tasks needed to be evaluated in parallel, as running them sequentially would take over 24 hours and delay feedback loops​.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reproducibility&lt;/strong&gt;: It had to be possible to trace every evaluation back to the exact version of the agent, datasets, and environment used. Local experiments or inconsistent setups were not acceptable​.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost control&lt;/strong&gt;: Each evaluation involved significant LLM API usage, typically costing USD 100+ per run. Tracking and managing these costs was essential​.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data preservation&lt;/strong&gt;: Results, logs, and artifacts needed to be stored reliably for analysis, debugging, and long-term tracking​.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Benchmarking with SWE-bench
&lt;/h3&gt;

&lt;p&gt;For a reliable signal, Junie adopted &lt;a href="https://www.swebench.com/" rel="noopener noreferrer"&gt;SWE-bench&lt;/a&gt;, a benchmark built from real GitHub issues and PRs. They also used SWE-bench Verified, a curated 500-task subset validated by OpenAI for clarity and feasibility.&lt;/p&gt;

&lt;p&gt;In parallel, Junie created in-house benchmarks for their internal monorepo (Java/Kotlin), Web stack, and Go codebases, continuously covering more languages and technologies by the benchmarks.&lt;/p&gt;

&lt;h3&gt;
  
  
  The operational challenge
&lt;/h3&gt;

&lt;p&gt;Running these large-scale evaluations posed operational challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spinning up consistent, isolated environments for each task.&lt;/li&gt;
&lt;li&gt;Managing dependencies and project setups.&lt;/li&gt;
&lt;li&gt;Applying patches generated by agents and running validations automatically.&lt;/li&gt;
&lt;li&gt;Collecting structured logs and metrics for deep analysis.&lt;/li&gt;
&lt;li&gt;Manual workflows wouldn’t scale. Junie needed automation that was fast, repeatable, and deeply integrated into their engineering stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TeamCity enabled that orchestration. With it, the Junie team built an evaluation pipeline that is scalable, traceable, and deeply integrated into their development loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;To support reliable, large-scale evaluation of its coding agents, Junie implemented an evaluation pipeline powered by TeamCity, a CI/CD solution developed by JetBrains.&lt;/p&gt;

&lt;p&gt;TeamCity orchestrates the execution of hundreds of tasks in parallel, manages isolated environments for each benchmark case, and coordinates patch validation and result collection.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If we tried running this locally, it just wouldn’t be realistic. A single evaluation would take a full day. That’s why we use TeamCity: to do everything in parallel, isolated environments, and to ensure the results are reproducible. - &lt;em&gt;Danila Savenkov, Team Lead, JetBrains Junie&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The setup enables the team to trace outcomes to specific agent versions, gather detailed logs for analysis, and run evaluations efficiently, while keeping infrastructure complexity and LLM usage costs under control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Execution pipeline design
&lt;/h3&gt;

&lt;p&gt;At the heart of the system is a composite build configuration defined using Kotlin DSL, which gives Junie full control over task orchestration. Each top-level evaluation run includes multiple build steps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfflvlqc025714qc45fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfflvlqc025714qc45fx.png" alt="Example of a build chain in TeamCity" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment setup
&lt;/h3&gt;

&lt;p&gt;Each coding task is paired with a dedicated environment, typically a pre-built Docker container with the necessary dependencies already installed. This guarantees consistency across runs and eliminates local setup variability​.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent execution
&lt;/h3&gt;

&lt;p&gt;Junie’s agent is launched against the task. It receives a full prompt, including the issue description, code structure, system commands, and guidelines. It then autonomously works through the problem, issuing actions such as file edits, replacements, and test runs​. &lt;/p&gt;

&lt;p&gt;The final output is a code patch meant to resolve the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Patch evaluation
&lt;/h3&gt;

&lt;p&gt;The generated patch is passed to the next build step, where TeamCity applies it to the project and runs the validation suite. This mimics the GitHub pull request flow – if the original tests were failing and now pass, the task is marked as successfully completed​.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metric logging
&lt;/h3&gt;

&lt;p&gt;Execution metadata, including logs, command traces, and success/failure flags, is exported to an open-source distributed storage and processing system. Junie uses it to store evaluation artifacts and perform large-scale analysis. &lt;/p&gt;

&lt;p&gt;With the solution’s support for SQL-like querying and scalable data processing, the team can efficiently aggregate insights across hundreds of tasks and track agent performance over time.&lt;/p&gt;

&lt;p&gt;Developers rely on this data to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track the percentage of solved tasks (their “North Star” metric).&lt;/li&gt;
&lt;li&gt;Analyze the average cost per task for LLM API usage.&lt;/li&gt;
&lt;li&gt;Break down agent behavior ( like the most frequent commands or typical failure points).&lt;/li&gt;
&lt;li&gt;Compare performance between agent versions​.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scalability through automation
&lt;/h3&gt;

&lt;p&gt;By using Kotlin DSL and TeamCity’s composable build model, Junie scales evaluations to hundreds of tasks per session – far beyond what could be managed manually. For larger datasets (typically 300-2000 tasks), each execution is spun up in parallel, minimizing runtime and allowing the team to test changes frequently.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We use Kotlin DSL to configure everything. When you have 13 builds, you can still manage them manually, but when it’s 399, or 500, or 280, it starts getting tricky. - &lt;em&gt;Danila Savenkov, Team Lead, JetBrains Junie&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Results: reproducible, scalable, insight-driven agent development
&lt;/h2&gt;

&lt;p&gt;TeamCity has enabled Junie to measure agent performance efficiently and at scale, making their development process faster, more reliable, and data-driven.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key outcomes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalable evaluation&lt;/strong&gt;: Tasks are evaluated in parallel, reducing runtime from 24+ hours to a manageable window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full reproducibility&lt;/strong&gt;: Every run is traceable to a specific agent version and dataset snapshot, which is crucial for tracking progress and debugging regressions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliable metrics&lt;/strong&gt;: Logs and outcomes from each task are automatically stored and analyzed. This allows deep introspection without relying on TeamCity for data retention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost awareness&lt;/strong&gt;: LLM usage is monitored per run and per-task, helping the team optimize both internal development and future product behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleaner feedback loops&lt;/strong&gt;: The ability to evaluate 100+ tasks per change helps the team distinguish real improvements from statistical noise.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>jetbrains</category>
      <category>teamcity</category>
      <category>agents</category>
      <category>evaluation</category>
    </item>
    <item>
      <title>Automate Your React App Deployment With JetBrains TeamCity</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Thu, 20 Feb 2025 12:34:02 +0000</pubDate>
      <link>https://forem.com/teamcity/automate-your-react-app-deployment-with-jetbrains-teamcity-4cn0</link>
      <guid>https://forem.com/teamcity/automate-your-react-app-deployment-with-jetbrains-teamcity-4cn0</guid>
      <description>&lt;p&gt;&lt;em&gt;This tutorial was brought to you by &lt;a href="https://kumarharsh.me/" rel="noopener noreferrer"&gt;Kumar Harsh&lt;/a&gt;, a software developer and technical author.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you regularly work with React projects, you probably already know how tricky it can be to deploy them smoothly. Issues like manual errors, inconsistent deployment practices, and slow iteration cycles often turn React app deployment into a challenging process and a source of frequent headaches. Effective use of automation can help reduce those headaches and significantly improve the transition from code to users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/teamcity/" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt;, a continuous integration and continuous deployment (CI/CD) platform from JetBrains, is designed to simplify deployment pipelines. It offers features like build automation and optimization, detailed test reporting, and secure credential management. &lt;/p&gt;

&lt;p&gt;By securely automating your deployment workflow, TeamCity helps reduce errors, improve consistency, and accelerate delivery, allowing your team to focus on building great applications.&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll learn how to set up an automated deployment pipeline with &lt;a href="https://jetbrains.com/teamcity/pipelines" rel="noopener noreferrer"&gt;TeamCity Pipelines&lt;/a&gt;. You’ll learn how to configure TeamCity to deploy a React app from a GitHub repository to an Amazon S3 bucket, making it ready to serve as a static website.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Before you get started, here’s what you’ll need to follow along:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A GitHub account.&lt;/li&gt;



&lt;li&gt;An AWS account. The pipeline you’ll create in this tutorial will deploy the final app to an Amazon S3 bucket. Since you only need to use S3, a &lt;a href="https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&amp;amp;all-free-tier.sort-order=asc&amp;amp;awsf.Free%20Tier%20Types=*all&amp;amp;awsf.Free%20Tier%20Categories=*all" rel="noopener noreferrer"&gt;free AWS account&lt;/a&gt; will work.&lt;/li&gt;



&lt;li&gt;A &lt;a href="https://jetbrains.com/teamcity/pipelines" rel="noopener noreferrer"&gt;TeamCity Pipelines&lt;/a&gt; account. If you don’t have one, you can sign up for a &lt;a href="https://www.jetbrains.com/teamcity/download/" rel="noopener noreferrer"&gt;14-day free trial&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have these ready, start by forking this GitHub repo to your own GitHub account:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/krharsh17/teamcity-react-test-app" rel="noopener noreferrer"&gt;&lt;code&gt;https://github.com/krharsh17/teamcity-react-test-app&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above repo contains a React 18 app created using &lt;a href="https://vite.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;. The app’s home page displays framework logos and includes a button that tracks how many times it’s clicked:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F1_Output-of-the-React-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F1_Output-of-the-React-app.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Output of the React app&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The repo also contains two integration tests in the &lt;code&gt;src/App.test.jsx&lt;/code&gt; file that check whether the &lt;code&gt;App&lt;/code&gt; component is rendered and if the button and the counter are working.&lt;/p&gt;

&lt;p&gt;You can enter the following commands in a terminal window at the root of the repo to run the tests for yourself:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn &amp;amp;&amp;amp; yarn test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here’s what the output should look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;RUN  v0.34.6 /Users/kumarharsh/Work/Draft/teamcity-react/teamcity-react-test-app

 ✓ src/App.test.jsx (2)

   ✓ App (2)

     ✓ renders

     ✓ should increase count by 1

 Test Files  1 passed (1)

      Tests  2 passed (2)

   Start at  23:05:51

   Duration  642ms (transform 31ms, setup 0ms, collect 146ms, tests 26ms, environment 284ms, prepare 51ms)

✨  Done in 1.61s.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This indicates that the tests ran successfully on your local system. At this point, you’re ready to start building the CI/CD pipeline.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Setting up TeamCity&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Let’s start by creating a new pipeline in TeamCity. Once you’ve signed up for TeamCity Cloud, you should see a loading screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F2_TeamCity-Cloud-server-starting-1-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F2_TeamCity-Cloud-server-starting-1-1.png" alt="" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TeamCity Cloud server starting&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once the server is up, here’s what the dashboard should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F3_TeamCity-Cloud-dashboard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F3_TeamCity-Cloud-dashboard.png" alt="" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TeamCity Pipelines dashboard&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click the blue &lt;em&gt;Create new pipeline&lt;/em&gt; button in the middle of the page, then authenticate with your Git platform:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F4_Logging-in-to-a-VCS-provider.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F4_Logging-in-to-a-VCS-provider.png" alt="" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Logging in to a VCS provider&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Authenticate with GitHub once again. TeamCity will then ask you to choose the repo you’d like to deploy in your first pipeline. Type “teamcity-react-test-app” in the search bar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F5_Choosing-your-forked-repo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F5_Choosing-your-forked-repo.png" alt="" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Choosing your forked repo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Select the forked repo and click &lt;em&gt;Create&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F6_Creating-the-pipeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F6_Creating-the-pipeline.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Creating the pipeline&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will set up your new pipeline. Here’s what its &lt;em&gt;Edit&lt;/em&gt;&lt;strong&gt; &lt;/strong&gt;page should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F7_Newly-created-pipeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F7_Newly-created-pipeline.png" alt="" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Newly created pipeline&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At this point, you’re ready to start developing the steps and jobs in the pipeline.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Creating a simple, sequential pipeline&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;You’ll first create a straightforward pipeline that installs dependencies, runs tests, creates a build, sets up AWS credentials, and finally pushes the built artifacts to the S3 bucket. Then, you’ll optimize it by splitting it into multiple jobs that can reuse steps and run in parallel as needed.&lt;/p&gt;

&lt;p&gt;Hover over the name of the job (&lt;strong&gt;Job 1&lt;/strong&gt;) in the right pane and click the pencil icon that pops up to edit the name:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F8_Editing-the-job-name.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F8_Editing-the-job-name.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Editing the job name&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Rename the job “Deploy to S3.” Then, click the &lt;strong&gt;NODE.JS&lt;/strong&gt; icon under the &lt;strong&gt;Steps&lt;/strong&gt; section to add a Node.js-based pipeline step:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F9_Adding-a-new-step.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F9_Adding-a-new-step.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Adding a new step&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will open another sidebar that asks for the details of the steps, including the step name, the working directory (which is the repo root by default), and the shell script you’d like to run as part of this step:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F10_Editing-the-step-details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F10_Editing-the-step-details.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Editing the step details&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Enter “Install dependencies” as the step name and &lt;code&gt;yarn&lt;/code&gt; for the shell script. Click the blue &lt;strong&gt;Done&lt;/strong&gt; button in the bottom left-hand corner of the sidebar to add the step to the job. Here’s what the job should look like now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F11_Updated-job.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F11_Updated-job.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated job&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Adding the test and build steps&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Now, add two more steps to the job with the following details:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;“Run test”, with the shell script &lt;code&gt;yarn test&lt;/code&gt;.&lt;/li&gt;



&lt;li&gt;“Build”, with the shell script &lt;code&gt;yarn build&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s what the job should look like when you’re done adding the two steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F12_Updated-job-with-three-steps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F12_Updated-job-with-three-steps.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated job with three steps&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At this point, you can try out the pipeline to see if it runs the tests and builds the app correctly by clicking the blue &lt;strong&gt;Save and run&lt;/strong&gt; button in the top right-hand corner of the page. Here’s what the output should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F13_Results-of-the-first-run.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F13_Results-of-the-first-run.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Results of the first run&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can expand the sections for each of the steps 1 through 3 to learn more about how they ran. Try expanding step 2 to view the test results. You’ll notice results similar to what you received when you ran the tests locally:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F14_Test-execution-logs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F14_Test-execution-logs.png" alt="" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Test execution logs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This indicates that the test and build steps are working correctly.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Preparing the S3 bucket for deployment&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, you’ll be deploying the built React app to an Amazon S3 bucket. But before you do that, you’ll need to create a new S3 bucket and configure it to serve a static website. You can find detailed instructions on how to do that in &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/HostingWebsiteOnS3Setup.html" rel="noopener noreferrer"&gt;this AWS tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s an overview of the steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new S3 bucket with a name (for example, &lt;code&gt;myawsbucket-kh&lt;/code&gt;) and default settings.&lt;/li&gt;



&lt;li&gt;On the bucket details page, go to the &lt;strong&gt;Properties&lt;/strong&gt; tab. Scroll down to find the &lt;strong&gt;Static website hosting&lt;/strong&gt; section and click the &lt;strong&gt;Edit&lt;/strong&gt; button:&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXcrz8ajCA1SUQS5GMlJtcuTB-lc6oWDdu_xx_g3ssCO7SegaZuL3XXkQslWUkRXDhdQDw8gVKdCTeFY6oVUiHp1rml6K2c_8eCI7rgBypqfHmr3idYwVKipevKjvhRGxTAUYmY0Fw%3Fkey%3DeGjCvBRhTKrA4HpIyT_bjyV5" alt="Enabling static website hosting" width="1600" height="789"&gt;&lt;em&gt;Enabling static website hosting&lt;/em&gt;
&lt;/li&gt;



&lt;li&gt;Choose &lt;strong&gt;Enable&lt;/strong&gt; under &lt;strong&gt;Static website hosting&lt;/strong&gt; and specify the &lt;strong&gt;Index document&lt;/strong&gt; as index.html. Click the &lt;strong&gt;Save changes&lt;/strong&gt; button at the bottom of the page when done. Here’s what the &lt;strong&gt;Static website hosting&lt;/strong&gt; section should look like now:&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXd2yqvENZLYphG27foOr0HRqtpR4L-Zvu1EpWh-0ufFKBlq-7W_-VG8vFLD-ZnOVY_sZLh1kQKdaNZ0ixyrtNAGE4EzhqGdhAdDLrHQPMluarwymIZvTEaQRXR4ybsz5pBGGS9H%3Fkey%3DeGjCvBRhTKrA4HpIyT_bjyV5" alt="Static website hosting enabled" width="1600" height="789"&gt;&lt;a href="https://i.imgur.com/5BLVx8V.png" rel="noopener noreferrer"&gt;&lt;em&gt;&lt;br&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt;Static website hosting enabled&lt;/em&gt;You’ll also find the website endpoint at the bottom of this page. This is where you’ll be able to access the website once it’s deployed.&lt;/li&gt;



&lt;li&gt;You also need to enable public access to the bucket. To do that, head over to the &lt;strong&gt;Permissions&lt;/strong&gt; tab from the same page and click the &lt;strong&gt;Edit&lt;/strong&gt; button in the &lt;strong&gt;Block public access (bucket settings)&lt;/strong&gt; section:&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXcLRmeyH5M9aIi_-4_4RNDrIdVu3ZFX0PA5_45uNsRbMTTAyWCK3-ivG4Y3erWcmCCExGT58ZQr0--B8W8dUA0N8PJPmiYgTAZB1H6xzCrDyULj4uUcqSRW_PrYCSudf79SYlIDfg%3Fkey%3DeGjCvBRhTKrA4HpIyT_bjyV5" alt="Editing public access settings" width="1600" height="789"&gt;&lt;em&gt;Editing public access settings&lt;/em&gt;On the resulting page, you need to uncheck the &lt;strong&gt;Block &lt;em&gt;all&lt;/em&gt; public access&lt;/strong&gt; option and click the &lt;strong&gt;Save changes&lt;/strong&gt; button in the bottom right-hand corner:&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXf94MBr6MFNcVg3FaLhDAtydktGVUAIO0qZWgzPRArPA1nR69HYbhcuMvRW_Q2KuH8MfqOTMQ-KBBGizCA5ZWgJQfyvS5-gy9n63aeJMz8g7lIrtyX53SaVE6sBqvMmBL_KL_tqgA%3Fkey%3DeGjCvBRhTKrA4HpIyT_bjyV5" alt="Enabling public access" width="1600" height="789"&gt;&lt;em&gt;Enabling public access&lt;/em&gt;Once you’ve enabled public access, you can start uploading files to this bucket and access the website at the URL you retrieved earlier.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy and store the S3 bucket name somewhere safe. You also need to generate an AWS access key ID and secret. Before you do that, it’s best to create a dedicated AWS IAM user for the CI/CD pipeline to avoid exposing your admin user’s privileges unnecessarily. &lt;/p&gt;

&lt;p&gt;To do that, navigate to the &lt;a href="https://us-east-1.console.aws.amazon.com/iam/home?region=us-east-1#/users" rel="noopener noreferrer"&gt;AWS IAM Users page&lt;/a&gt; via your AWS console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F16_Users-page-via-the-AWS-IAM-console.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F16_Users-page-via-the-AWS-IAM-console.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Users page via the AWS IAM console&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On this page, click the orange &lt;strong&gt;Create user&lt;/strong&gt; button to create a new user. Feel free to give it any name you like. For permissions, choose &lt;strong&gt;Attach policies directly&lt;/strong&gt; under &lt;strong&gt;Permission options&lt;/strong&gt; and search for and add the &lt;code&gt;AmazonS3FullAccess&lt;/code&gt; policy to the user. Here’s what the user should look like on the review page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F17_Reviewing-the-newly-proposed-user.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F17_Reviewing-the-newly-proposed-user.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reviewing the newly proposed user&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Create user&lt;/strong&gt; button in the bottom right-hand corner of the page. Once the user is created, click its name on the &lt;strong&gt;Users &lt;/strong&gt;page to view its details:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F18_Viewing-the-newly-created-users-details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F18_Viewing-the-newly-created-users-details.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Viewing the newly created user’s details&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here’s what the user details page will look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F19_user-details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F19_user-details.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;User details&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Security credentials&lt;/strong&gt; tab and scroll down to find the &lt;strong&gt;Access keys&lt;/strong&gt; section:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F20_Finding-the-access-keys-section.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F20_Finding-the-access-keys-section.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Finding the access keys section&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Create access key&lt;/strong&gt; button. On the page that opens, choose &lt;strong&gt;Command line interface (CLI)&lt;/strong&gt; under the &lt;strong&gt;Use case&lt;/strong&gt; and check the confirmation checkbox at the bottom of the page before clicking the &lt;strong&gt;Next&lt;/strong&gt; button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F21_Creating-the-access-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F21_Creating-the-access-key.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Creating the access key&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can skip adding tags to the access key and click the &lt;strong&gt;Create access key&lt;/strong&gt; button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F22_Skipping-tags-and-creating-the-access-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F22_Skipping-tags-and-creating-the-access-key.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Skipping tags and creating the access key&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The next page will display the access key and the secret access key values. Copy them and store them safely. You’ll use them in the next step of the pipeline to upload built artifacts to the S3 bucket through the AWS CLI.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can safely provide your pipeline with the AWS secrets through TeamCity’s secrets. However, the recommended approach to handle infrastructure integration with CI/CD pipelines is to allow administrators to connect and manage cloud platforms while only providing pipelines (and related users) the ability to use those connections as part of the pipeline steps only, with no access to the secret keys or values at all. To learn more about implementing this approach, check out TeamCity’s &lt;/em&gt;&lt;a href="https://blog.jetbrains.com/teamcity/2022/12/introducing-aws-connection/" rel="noopener noreferrer"&gt;&lt;em&gt;AWS Connection&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Adding the deploy steps&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;You now have everything you need to add the deploy steps. To do that, you’ll need to add two more steps to your TeamCity pipeline as you did before.&lt;/p&gt;

&lt;p&gt;First, add a step named “Configure AWS credentials.” Set the step type to &lt;strong&gt;Script&lt;/strong&gt; and use the following custom script value:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;aws configure set aws_access_key_id "%AWS_ACCESS_KEY_ID%"

aws configure set aws_secret_access_key "%AWS_SECRET_ACCESS_KEY%"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This step uses the AWS CLI to configure your AWS account credentials by accessing the &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; TeamCity secrets.&lt;/p&gt;

&lt;p&gt;Next, add a step named “Push to S3.” Set its type as &lt;strong&gt;Script&lt;/strong&gt; and add the following custom script value:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;aws s3 cp dist s3://%AWS_S3_BUCKET_NAME%/ --recursive&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With the AWS CLI properly configured, this step will upload the contents of the dist directory (generated by the build step) to the S3 bucket, using the bucket name stored in the TeamCity secret &lt;code&gt;AWS_S3_BUCKET_NAME&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can use the AWS CLI directly inside the pipeline because it’s preinstalled on default JetBrains-hosted agents. &lt;/em&gt;&lt;a href="https://www.jetbrains.com/help/teamcity/cloud/jetbrains-hosted-agents.html#Agent+Software" rel="noopener noreferrer"&gt;&lt;em&gt;Here’s a list of all the software resources&lt;/em&gt;&lt;/a&gt;&lt;em&gt; that you get out of the box when using JetBrains-hosted runners on TeamCity Cloud.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is what the job should look like when you’re done adding the steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F23_Deploy-steps-added-to-the-pipeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F23_Deploy-steps-added-to-the-pipeline.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Deploy steps added to the pipeline&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You’ll notice that the “Deploy to S3” job now shows up in yellow with a warning that says “No compatible agent”. This is because some of the steps in the job rely on pipeline secrets that aren’t defined yet. You can fix that by clicking the &lt;strong&gt;Pipeline settings&lt;/strong&gt; link right above the job and clicking the plus (&lt;strong&gt;+&lt;/strong&gt;) icon to the right of the &lt;strong&gt;No Secrets&lt;/strong&gt; section in the right pane:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F24_Adding-secrets-to-the-pipeline-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F24_Adding-secrets-to-the-pipeline-.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Adding secrets to the pipeline&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will show some text input fields in that section that will allow you to add secret names and values. You need to add the following secrets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;: Your AWS access key.&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;: Your AWS access key secret.&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;AWS_S3_BUCKET_NAME&lt;/code&gt;: The name of your S3 bucket.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you’ve defined and saved these values, you’ll notice the yellow highlight and warning text are gone:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F25_Pipeline-ready-to-run.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F25_Pipeline-ready-to-run.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pipeline ready to run&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can now click the &lt;strong&gt;Save and run&lt;/strong&gt; button in the top right-hand corner to save and run the updated pipeline. Here’s what the output should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F26_Test-run-of-the-updated-pipeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F26_Test-run-of-the-updated-pipeline.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Test run of the updated pipeline&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This means that your app was successfully built and deployed to your S3 bucket. You can check the bucket to see if the files were actually added there:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F26_S3-bucket-with-build-artifacts-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F26_S3-bucket-with-build-artifacts-.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;S3 bucket with build artifacts&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can also visit the public website URL you received earlier to view the deployed website:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F27_Deployed-website-as-a-result-of-the-pipeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F27_Deployed-website-as-a-result-of-the-pipeline.png" alt="" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Deployed website as a result of the pipeline&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since the pipeline was created with a GitHub VCS repository, it’s automatically configured to monitor the main branch for new commits and trigger whenever it detects changes.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Optimizing the pipeline&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;You can make some tweaks to optimize this pipeline further. Currently, there are only a small number of tests, which shouldn’t cause a performance bottleneck. However, if you end up having a large number of tests, especially integration tests that might require extensive setup and teardown in some cases, the test step could become quite time-consuming.&lt;/p&gt;

&lt;p&gt;The pipeline is configured to only proceed to the build and the deploy steps once the tests have been completed successfully. &lt;/p&gt;

&lt;p&gt;If you’re setting up a pipeline on a production branch that only receives commits after they’ve been approved as part of a PR or another review process earlier, you can consider running the tests and the build in parallel to save some time. &lt;/p&gt;

&lt;p&gt;If either of the two fails, the deploy step can be skipped since you wouldn’t want to deploy a version that doesn’t satisfy internal tests or if you’re not able to generate a successful build for it.&lt;/p&gt;

&lt;p&gt;You can use TeamCity’s parallel builds to achieve this. Since this will require you to split the pipeline into multiple jobs, TeamCity can reuse job results to avoid rerunning jobs if the last run was successful and no new changes have been made since then. &lt;/p&gt;

&lt;p&gt;This approach saves CI/CD minutes when testing the pipeline with the same commit multiple times. Alternatively, you can configure the pipeline to reupload (without rebuilding) the website to the S3 bucket if needed.&lt;/p&gt;

&lt;p&gt;To implement these optimizations, you’ll first need to split the steps from the “Deploy to S3” job into three jobs.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Create build&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Create Build&lt;/strong&gt; job will just install project dependencies and create the build. For that, you need to add two steps to it: a Node.js step called “Install dependencies” with the command &lt;code&gt;yarn&lt;/code&gt; and another Node.js step called “Create build” with the command &lt;code&gt;yarn build&lt;/code&gt;. Here’s what the job will look like when you’ve added the steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F28_New-build-job-with-two-steps-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F28_New-build-job-with-two-steps-.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;New build job with two steps&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You also need to scroll down and configure the artifacts for this job. Since the output of this job will be used by the “Deploy to S3” job to deploy the app to the S3 bucket, you need to click the plus sign icon to the right of the &lt;strong&gt;Artifacts&lt;/strong&gt; section and enter &lt;code&gt;./dist/*&lt;/code&gt; in the input field that pops up:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F29_Updated-artifacts-path-in-the-build-job-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F29_Updated-artifacts-path-in-the-build-job-.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated artifacts path in the build job&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Run tests&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Now, create another job named “Run Tests” and add two steps: “Install dependencies” (same as before) and another Node step called “Run tests” with the command yarn test. Here’s what the job will look like when you’ve added the steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F30_new-tests-job.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F30_new-tests-job.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.imgur.com/4fmND3I.png" rel="noopener noreferrer"&gt;&lt;em&gt;&lt;br&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt;New tests job&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You don’t need to configure any artifacts for this job since it doesn’t generate any output files after running the tests. You could, however, choose to export test results in a file and add another job to the pipeline to upload the results to a test results analysis platform.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Deploy to S3&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Finally, you need to update the “Deploy to S3” job to run only after the other two jobs have finished running successfully. Since the other steps are now being run as part of the other two jobs, this job only needs to run the “Configure AWS credentials” and “Push to S3” steps. &lt;/p&gt;

&lt;p&gt;Here’s what the steps list will look like when you’ve deleted the first three steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F31_new-deploy-job.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F31_new-deploy-job.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;New deploy job&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You need to check both &lt;strong&gt;Create Build&lt;/strong&gt; and &lt;strong&gt;Run Tests&lt;/strong&gt; under &lt;strong&gt;Dependencies&lt;/strong&gt; since the deploy job depends on those two jobs running successfully. Here’s how the job’s details (and the pipeline) will look when you do that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F32_Job-dependencies-configured.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F32_Job-dependencies-configured.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Job dependencies configured&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click the dropdown that says &lt;strong&gt;Ignore artifacts&lt;/strong&gt; next to the &lt;strong&gt;Create Build&lt;/strong&gt; checkbox under &lt;strong&gt;Dependencies&lt;/strong&gt; and change its status to &lt;strong&gt;Use artifacts&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F33_Artifact-usage-configured-for-the-job.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F33_Artifact-usage-configured-for-the-job.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Artifact usage configured for the job&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Scroll down to the &lt;strong&gt;Optimizations&lt;/strong&gt; section, where you’ll see that the &lt;strong&gt;Reuse Job Results&lt;/strong&gt; toggle is on by default:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F34_Reuse-job-results-toggle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F34_Reuse-job-results-toggle.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reuse job results toggle&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Switch the toggle to off. Disabling this ensures that, regardless of whether the repository receives a new commit, each pipeline run updates the last successful build artifacts on the S3 bucket. This can help in situations where the contents of the S3 bucket have been manually modified and you need to restore them to the last successful build state.&lt;/p&gt;

&lt;p&gt;Now, you can click the &lt;strong&gt;Save and run&lt;/strong&gt; button and watch as the pipeline tests and builds your code before deploying it to S3.&lt;/p&gt;

&lt;p&gt;You can watch as the various steps of the pipeline run in order to build, test, and deploy your React app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F35_Optimized-pipeline-run-in-progress-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F35_Optimized-pipeline-run-in-progress-.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Optimized pipeline run in progress&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can explore the execution logs of each of the jobs and their steps by clicking the job and then navigating through the logs in the right pane. Once the build completes running, here’s what the page will look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F36_Successful-test-results-of-the-optimized-pipeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2F36_Successful-test-results-of-the-optimized-pipeline.png" alt="" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Successful test results of the optimized pipeline&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can now try pushing a new commit to your forked GitHub repo and watch the pipeline get triggered automatically. Within minutes, it will test, build, and deploy your updated React website to the S3 bucket!&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;This tutorial explained how to set up an automated deployment pipeline with TeamCity to deploy a React app from GitHub to an Amazon S3 bucket. This process eliminates manual intervention, ensuring your app is deployed faster, more reliably, and with consistent results. &lt;/p&gt;

&lt;p&gt;Automating your React app deployment not only saves time but also minimizes errors and improves overall development workflows, allowing your team to focus on delivering value to users.&lt;/p&gt;

&lt;p&gt;With tools like &lt;a href="https://www.jetbrains.com/help/teamcity/build-approval.html" rel="noopener noreferrer"&gt;Build Approval&lt;/a&gt;, TeamCity allows you to add an extra layer of security by ensuring that only authorized builds are deployed to production. Meanwhile, as you saw in the tutorial, &lt;a href="https://www.jetbrains.com/help/teamcity/build-chain.html" rel="noopener noreferrer"&gt;build chains&lt;/a&gt; (or pipelines) enable you to manage complex workflows by breaking them into smaller, interdependent tasks, making large projects easier to handle. &lt;/p&gt;

&lt;p&gt;These features, combined with TeamCity’s comprehensive reporting and automation capabilities, make it a powerful choice for your deployment needs. Make sure to give &lt;a href="https://jetbrains.com/teamcity/pipelines" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt; a try for your next React app project!&lt;/p&gt;

</description>
      <category>react</category>
      <category>cicd</category>
      <category>teamcity</category>
      <category>jetbrains</category>
    </item>
    <item>
      <title>What Is DAST? A Guide to Dynamic Application Security Testing</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Thu, 06 Feb 2025 12:14:15 +0000</pubDate>
      <link>https://forem.com/teamcity/what-is-dast-a-guide-to-dynamic-application-security-testing-3kb9</link>
      <guid>https://forem.com/teamcity/what-is-dast-a-guide-to-dynamic-application-security-testing-3kb9</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was brought to you by &lt;a href="https://www.linkedin.com/in/mgkeib/" rel="noopener noreferrer"&gt;Matt Keib&lt;/a&gt;, draft.dev. &lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dynamic application security testing (DAST) is a security testing method designed to identify vulnerabilities in applications while running. Unlike static testing methods, which analyze code at rest, DAST interacts with live applications and mimics real-world attacks to uncover security flaws. This makes DAST particularly effective for detecting issues that only occur when an application is running.&lt;/p&gt;

&lt;p&gt;Within the bigger picture of security testing methodologies, DAST stands out for targeting the operational state of applications and APIs. Unlike &lt;a href="https://www.jetbrains.com/teamcity/ci-cd-guide/concepts/static-code-analysis/" rel="noopener noreferrer"&gt;static application security testing&lt;/a&gt; (SAST), which analyzes source code, or &lt;a href="https://en.wikipedia.org/wiki/Interactive_application_security_testing" rel="noopener noreferrer"&gt;interactive application security testing&lt;/a&gt; (IAST), which combines runtime testing with code analysis, DAST focuses on identifying vulnerabilities that arise only during application execution.&lt;/p&gt;

&lt;p&gt;Thanks to its ability to simulate real-world attacks on live web applications and APIs, DAST can help uncover issues like authentication flaws, configuration errors, and runtime vulnerabilities, which are weaknesses often missed by static methods. This makes DAST an essential component for securing applications in production environments and protecting them against external threats.&lt;/p&gt;

&lt;p&gt;In this article, you’ll learn about DAST fundamentals, when it’s appropriate to use it, and how &lt;a href="https://www.jetbrains.com/teamcity/" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt; can help you maximize its effectiveness.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;What DAST is and how it works&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;DAST’s primary function is to assess live applications from an attacker’s perspective to identify runtime vulnerabilities. DAST uses an outside-in (or &lt;a href="https://www.jetbrains.com/teamcity/ci-cd-guide/faq/types-of-testing/" rel="noopener noreferrer"&gt;black box&lt;/a&gt;) testing approach, which evaluates applications in their runtime environment without resorting to accessing source code or internal details. &lt;/p&gt;

&lt;p&gt;Unlike other application security tools that analyze internal structures, DAST mimics external inputs by malicious actors and examines how the application responds, providing unique insights into potential vulnerabilities. In other words, the tool attempts to perform the very same exploits an attacker would in a real attack situation.&lt;/p&gt;

&lt;p&gt;One of the defining characteristics of DAST tools is their ability to provide &lt;a href="https://www.techopedia.com/definition/31721/actionable-insight" rel="noopener noreferrer"&gt;actionable insights&lt;/a&gt;, including comprehensive reports detailing vulnerabilities, potential impacts, and remediation recommendations. &lt;/p&gt;

&lt;p&gt;These tools not only identify flaws, misconfigurations, and issues in a running application but also provide recommendations on how to properly address them. This is especially important today, as developers must balance tight deadlines with meeting compliance standards and implementing guidelines that safeguard customer data from breaches and unauthorized access.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;DAST vs. other types of security testing&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;While DAST excels at runtime testing, other methods like SAST and IAST address different stages of the development lifecycle. SAST analyzes source code before execution, helping developers catch issues early during coding (this approach is also known as &lt;a href="https://en.wikipedia.org/wiki/Shift-left_testing" rel="noopener noreferrer"&gt;shift-left&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;On the other hand, IAST combines elements of both static and dynamic testing, offering insights by monitoring the application during runtime while also linking findings to the specific code that raised concerns. This helps developers reduce overhead while focusing on the faulty segments they must fix to remediate active vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXf5j3W0zPN7kDkbEa7wW6YyRuBIodu1IPgrHFu5FMDfrBB0FiHJsHGeEBzO9h2jKKb6UfhYGXrzHKLdiLh_N3dp1LMGYV3fiQ_gSIaEN5c6bP0jjm_v5hh6yhdxfiBxOmmHOU2KCg%3Fkey%3DhZxfSX6kzxMRp3zBAhZ_9Bhg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXf5j3W0zPN7kDkbEa7wW6YyRuBIodu1IPgrHFu5FMDfrBB0FiHJsHGeEBzO9h2jKKb6UfhYGXrzHKLdiLh_N3dp1LMGYV3fiQ_gSIaEN5c6bP0jjm_v5hh6yhdxfiBxOmmHOU2KCg%3Fkey%3DhZxfSX6kzxMRp3zBAhZ_9Bhg" alt="" width="1600" height="834"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike SAST, which focuses on internal code structure, DAST evaluates the application from an external perspective, making it indispensable for detecting vulnerabilities that arise only during execution. &lt;/p&gt;

&lt;p&gt;For example, a runtime vulnerability like exposing sensitive data in API responses or failing to invalidate a session after logout could go unnoticed in static analysis but would be detected by DAST. &lt;/p&gt;

&lt;p&gt;Compared to IAST, DAST is less invasive, as it doesn’t require integration into the application’s codebase or runtime environment, nor does it involve deploying sensors into the source code. &lt;/p&gt;

&lt;p&gt;This simplicity makes DAST easier to implement and allows teams to switch between DAST tools with minimal friction if needed. &lt;/p&gt;

&lt;p&gt;To enhance security, DAST should be combined with SAST for broader visibility into risks. Modern DAST tools can seamlessly integrate into DevOps and CI/CD pipelines, enabling early-stage vulnerability mitigation through a shift-left approach.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Key features of DAST tools&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;DAST tools provide a range of features designed to streamline and enhance the security testing process, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scanning and mapping:&lt;/strong&gt; DAST tools initiate the testing process that simulates user interactions with the application. They send HTTP requests to map out all pages, links, functions, and entry points, including those defined in API documents. This step ensures thorough coverage of the application by uncovering all potential flaws that may open a door to attackers.
&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Analysis of application responses:&lt;/strong&gt; The tool then examines the application’s responses, looking for &lt;a href="https://en.wikipedia.org/wiki/Anomaly_detection" rel="noopener noreferrer"&gt;anomalies&lt;/a&gt;, error messages, and unexpected behavior that could indicate vulnerabilities. Identified issues, such as misconfigurations or runtime errors, are recorded for further review.
&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Attack simulation:&lt;/strong&gt; At this stage, DAST simulates common attacks like &lt;a href="https://www.cloudflare.com/learning/security/threats/sql-injection/" rel="noopener noreferrer"&gt;SQL injection&lt;/a&gt;, &lt;a href="https://www.cloudflare.com/learning/security/threats/cross-site-scripting/" rel="noopener noreferrer"&gt;cross-site scripting&lt;/a&gt; (XSS), and &lt;a href="https://www.cloudflare.com/learning/security/threats/cross-site-request-forgery/" rel="noopener noreferrer"&gt;cross-site request forgery&lt;/a&gt; (CSRF) to detect vulnerabilities. This process highlights issues such as input validation flaws, authentication errors, and data exposure risks that malicious actors could exploit.
&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Comprehensive reporting:&lt;/strong&gt; After scanning and analysis, DAST tools generate detailed reports that outline detected vulnerabilities together with their severity, as well as suggested remediation steps. These reports guide development and security teams in prioritizing fixes timely and effectively.This is very useful for complying with the respective SLAs of security teams, ensuring a swift resolution of incidents and improving the organization’s overall security posture. Additionally, granular reports are useful for internal communications such as those with the board or stakeholders, where security teams provide updates about the application’s security posture.
&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Potential false positives:&lt;/strong&gt; To ensure accuracy, modern DAST tools include mechanisms to minimize false positives. However, human validation and prioritization are often necessary to confirm the relevance and impact of flagged vulnerabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXfPYKCBn-YBS_9nuXnIPWtc1WtNf2ZlMG6aoMTBDVs8w9pBWYKHZF8nNxp7yrHrMW8iGxi0DOHx-vet4rdblbCKtXtAiysGFS4Dfn2SZnd60mGWefnslMfX9Aq4gtvy8LCF6JwvMA%3Fkey%3DhZxfSX6kzxMRp3zBAhZ_9Bhg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXfPYKCBn-YBS_9nuXnIPWtc1WtNf2ZlMG6aoMTBDVs8w9pBWYKHZF8nNxp7yrHrMW8iGxi0DOHx-vet4rdblbCKtXtAiysGFS4Dfn2SZnd60mGWefnslMfX9Aq4gtvy8LCF6JwvMA%3Fkey%3DhZxfSX6kzxMRp3zBAhZ_9Bhg" alt="" width="1600" height="1130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These features enable teams to proactively identify and address potential security flaws, minimizing risks and enhancing overall application security.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Best practices for effective DAST&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Implementing DAST effectively requires a strategy that prioritizes regular and comprehensive scanning to ensure consistent identification of risks and vulnerabilities. &lt;/p&gt;

&lt;p&gt;Regular scans help you stay ahead of emerging threats and verify that updates or new features of the application don’t introduce security gaps. &lt;/p&gt;

&lt;p&gt;In-depth coverage should include all aspects of the application, including APIs and single-page functionalities, to ensure no critical vulnerabilities remain hidden. &lt;/p&gt;

&lt;p&gt;Scheduling scans at regular intervals or after significant updates will contribute to consistent monitoring and reduce the chances of overlooking new vulnerabilities or entry points for attackers.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Combining DAST with other application security testing tools&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Integrating DAST with other security testing efforts enhances an organization’s security posture by addressing vulnerabilities at different stages of the software development lifecycle. &lt;/p&gt;

&lt;p&gt;Combining DAST with SAST allows teams to identify both static and runtime vulnerabilities, ensuring a more detailed risk assessment. While SAST analyzes the application’s source code for structural weaknesses, DAST focuses on vulnerabilities that emerge during runtime, offering visibility on vulnerabilities that may have slipped into production unnoticed.&lt;/p&gt;

&lt;p&gt;Including IAST in the mix bridges the gap between static and dynamic analysis by providing insights during application execution and linking vulnerabilities to specific sections of the code. &lt;/p&gt;

&lt;p&gt;Manual testing adds further depth in identifying context-specific risks or logic flaws that automated tools might overlook. Together, these methods create a layered security approach that reduces the likelihood of missed vulnerabilities.&lt;/p&gt;

&lt;p&gt;For example, consider an e-commerce application that processes user payments. SAST identifies a hard-coded API key in the source code, which is flagged as a potential security risk early in development. &lt;/p&gt;

&lt;p&gt;Later, during runtime testing, DAST detects that the same API key is being transmitted in plaintext over an insecure connection, exposing it to interception. Meanwhile, IAST links the issue to the specific code responsible for establishing the insecure connection, enabling the team to pinpoint and fix the root cause quickly. &lt;/p&gt;

&lt;p&gt;Manual testing then verifies the fix and ensures no other related vulnerabilities exist, providing confidence in the resolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXdQzQnZBsqfwZICTVwWuayMXrDBtYCoWYC7AeEUOPqq4kbpQpIuNw_92zGnCjg4dcQWAmnvvCq4FlM7FcxJShKfXeJFPRhhc6GPo_R5V0I5cAdlxwhqAHvDe_SwffnfK0lxas6z%3Fkey%3DhZxfSX6kzxMRp3zBAhZ_9Bhg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-rt.googleusercontent.com%2Fdocsz%2FAD_4nXdQzQnZBsqfwZICTVwWuayMXrDBtYCoWYC7AeEUOPqq4kbpQpIuNw_92zGnCjg4dcQWAmnvvCq4FlM7FcxJShKfXeJFPRhhc6GPo_R5V0I5cAdlxwhqAHvDe_SwffnfK0lxas6z%3Fkey%3DhZxfSX6kzxMRp3zBAhZ_9Bhg" alt="" width="1600" height="775"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A layered strategy not only maximizes coverage but also simplifies remediation efforts. For example, early-stage issues detected by SAST can be resolved before reaching runtime, reducing the scope of vulnerabilities flagged during DAST scans. &lt;/p&gt;

&lt;p&gt;Similarly, manual testing can validate and prioritize findings from automated tools and narrow down findings through a human-based dismissal of &lt;a href="https://csrc.nist.gov/glossary/term/false_positive" rel="noopener noreferrer"&gt;false positives&lt;/a&gt;, ensuring that resources are focused on the most critical risks.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Handling false positives and false negatives&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;First-generation DAST tools were often criticized for generating a significant number of false positives, creating extra workload for developers and security teams. In addition, they lacked automation capabilities and complete vulnerability validation. &lt;/p&gt;

&lt;p&gt;Current DAST tools can integrate with others like SAST, which helps confirm findings and reduce noise through the combination of different testing methods. Modern versions of DAST tools can cross-reference results, minimizing both false positives and &lt;a href="https://en.wikipedia.org/wiki/False_positives_and_false_negatives" rel="noopener noreferrer"&gt;false negatives&lt;/a&gt;, reducing overhead, and ensuring issues are detected.&lt;/p&gt;

&lt;p&gt;Additionally, modern DAST tools use advanced techniques like machine learning to improve accuracy. For instance, machine learning algorithms can analyze patterns in past scans to better distinguish legitimate vulnerabilities from false positives and continuously refine their detection capabilities. &lt;/p&gt;

&lt;p&gt;Other techniques, such as context-aware analysis and correlation with real-world attack patterns, further enhance their ability to detect meaningful issues while reducing overhead.&lt;/p&gt;

&lt;p&gt;Other techniques for managing false positives include tuning DAST configurations to match application-specific requirements and using predefined rule sets to exclude known, safe, and expected behaviors. Regularly updating vulnerability libraries ensures the tool accurately identifies real threats while reducing the likelihood of false positives caused by outdated patterns. &lt;/p&gt;

&lt;p&gt;False negatives can be resolved using manual reviews with DAST or combining it with IAST, which links detected vulnerabilities to specific code components for deeper insights. &lt;/p&gt;

&lt;p&gt;This way, organizations can ensure that DAST results are more accurate and actionable, and security teams have better data to prioritize and remediate vulnerabilities effectively.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;How TeamCity can help&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/teamcity/" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt; is a CI/CD solution that integrates DAST into CI/CD pipelines, embedding security testing directly into the development workflow. With its robust support for a wide range of languages and technologies, TeamCity ensures that projects of any size – whether they involve small teams or enterprise-scale applications – can seamlessly integrate DAST tools into their workflows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2Fteamcity-interface-dast.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2025%2F02%2Fteamcity-interface-dast.png" alt="" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/teamcity/features/test-automation/" rel="noopener noreferrer"&gt;Automating&lt;/a&gt; builds, tests, and deployments allows TeamCity to embed DAST scans at key stages of the software development lifecycle. Its integration capabilities extend to popular DAST tools, ensuring security testing runs alongside other CI/CD activities without disrupting productivity. &lt;/p&gt;

&lt;p&gt;The platform’s detailed &lt;a href="https://www.jetbrains.com/teamcity/features/build-infrastructure/" rel="noopener noreferrer"&gt;build&lt;/a&gt; logs and visual build chains provide insights into test results, making it easier for developers to pinpoint and address security vulnerabilities early.&lt;/p&gt;

&lt;p&gt;TeamCity reinforces a shift-left approach to security, ensuring testing is integrated earlier in the development cycle. Automated testing features, such as test parallelization and &lt;a href="https://www.jetbrains.com/teamcity/ci-cd-guide/concepts/flaky-tests/" rel="noopener noreferrer"&gt;flaky&lt;/a&gt; test detection, help developers maintain high-quality code while uncovering potential runtime vulnerabilities. With its emphasis on automation, scalability, and user-friendly integrations, TeamCity empowers teams to build secure and reliable software with confidence.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Identifying vulnerabilities during runtime allows DAST to address gaps left by other testing methods for thorough coverage of potential security flaws. Combining DAST with tools like SAST and IAST creates a layered security approach that maximizes visibility and optimizes remediation efforts.&lt;/p&gt;

&lt;p&gt;Before adopting DAST, evaluate your current security practices to identify areas where it can make the most significant impact, such as detecting runtime vulnerabilities in environments with third-party dependencies, rapidly changing codebases, and tight release schedules tracked through &lt;a href="https://www.jetbrains.com/teamcity/ci-cd-guide/devops-ci-cd-metrics/" rel="noopener noreferrer"&gt;DevOps metrics&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Once gaps are identified, the next step is to select a DAST solution that aligns with your team’s workflows and objectives. Choose a tool that integrates seamlessly into your development pipeline, allowing for regular scans and effective analysis of results. &lt;/p&gt;

&lt;p&gt;Incorporating these findings into your workflow ensures vulnerabilities are prioritized and resolved efficiently, reducing risks, enhancing productivity, and maintaining the speed and agility demanded by modern development practices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/teamcity/features/" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt; is a reliable solution that can support these efforts by offering seamless integration of DAST tools into CI/CD pipelines. Its complete set of features, such as automated testing and detailed build insights, empowers teams to detect and remediate vulnerabilities efficiently. With TeamCity, organizations can strengthen their security posture without compromising development speed or agility.&lt;/p&gt;

</description>
      <category>dast</category>
      <category>testing</category>
    </item>
    <item>
      <title>Introducing the New TeamCity Plugin for IntelliJ IDEA</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Thu, 12 Sep 2024 11:57:49 +0000</pubDate>
      <link>https://forem.com/teamcity/introducing-the-new-teamcity-plugin-for-intellij-idea-197</link>
      <guid>https://forem.com/teamcity/introducing-the-new-teamcity-plugin-for-intellij-idea-197</guid>
      <description>&lt;p&gt;We’re excited to announce the release of the updated TeamCity plugin for IntelliJ IDEA! 🎉 You can now download it directly &lt;a href="https://plugins.jetbrains.com/plugin/25142-teamcity-experimental-" rel="noopener noreferrer"&gt;from JetBrains Marketplace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using the plugin, you can trigger TeamCity builds directly from within your IDE and test any changes before committing them to the version control system.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/DAsFh0T2trg"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;Why get the new plugin?&lt;/h2&gt;

&lt;p&gt;This plugin has been built from the ground up to ensure it will eventually be able to replace the existing &lt;a href="https://plugins.jetbrains.com/plugin/1820-teamcity" rel="noopener noreferrer"&gt;TeamCity plugin&lt;/a&gt; once support for the most frequently used and requested features has been added. &lt;/p&gt;

&lt;p&gt;Here’s what’s new in the plugin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We’ve added functionality enabling you to link TeamCity projects and build configurations to your IDE project so that you only see build configurations related to your IDE project.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;With the help of the&lt;em&gt; &lt;/em&gt;remote run feature, you can run build configurations on your local changes without committing them to the VCS.&lt;/li&gt;



&lt;li&gt;The plugin’s tool window now contains a new &lt;em&gt;Personal Builds&lt;/em&gt; tab where past personal builds are listed. It also shows live updates of all builds executed using &lt;a href="https://www.jetbrains.com/help/teamcity/remote-run.html" rel="noopener noreferrer"&gt;the remote run&lt;/a&gt; feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8cu50mdyn0xca5prrys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8cu50mdyn0xca5prrys.png" alt=" " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now it’s possible to select a build configuration and watch its build status for each commit in the &lt;em&gt;VCS Log&lt;/em&gt; tool window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1fu0l51wubujy5q0sts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1fu0l51wubujy5q0sts.png" alt=" " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key benefits of this updated plugin include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The ability to manually configure which TeamCity projects relate to your code, giving you more control over your builds.
&lt;/li&gt;



&lt;li&gt;Enhanced performance that significantly reduces lag between your actions in the IDE and the TeamCity server's response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're actively developing this plugin and planning to add even more features in upcoming releases. Your feedback is critical in shaping the tool to better meet the needs of IntelliJ IDEA developers. &lt;/p&gt;

&lt;p&gt;You can install both &lt;a href="https://plugins.jetbrains.com/plugin/1820-teamcity" rel="noopener noreferrer"&gt;the old&lt;/a&gt; and &lt;a href="https://plugins.jetbrains.com/plugin/25142-teamcity-experimental-" rel="noopener noreferrer"&gt;new&lt;/a&gt; plugin versions side by side, so feel free to compare and explore!&lt;/p&gt;

&lt;h2&gt;How to get started with the TeamCity plugin for IntelliJ IDEA&lt;/h2&gt;

&lt;h3&gt;Initial setup&lt;/h3&gt;

&lt;p&gt;1. Download the plugin &lt;a href="https://plugins.jetbrains.com/plugin/25142-teamcity-experimental-" rel="noopener noreferrer"&gt;from Marketplace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;2. Once the plugin is installed, open your project in IntelliJ IDEA and invoke the plugin’s settings using the &lt;em&gt;Tools | TeamCity (Experimental) | Settings…&lt;/em&gt; menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fng8md4oc66whg8vih8sq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fng8md4oc66whg8vih8sq.png" alt=" " width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3. Click &lt;em&gt;Log In&lt;/em&gt; and enter the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server URL – the HTTP(S) address of your TeamCity server.&lt;/li&gt;



&lt;li&gt;Access token – your &lt;a href="https://www.jetbrains.com/help/teamcity/configuring-your-user-profile.html#Managing+Access+Tokens" rel="noopener noreferrer"&gt;user access token&lt;/a&gt; that can be generated on the &lt;em&gt;Your Profile | Access Tokens &lt;/em&gt;page in TeamCity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxx4alsu9apt4v04jdxs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxx4alsu9apt4v04jdxs.png" alt=" " width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the new plugin, you can link build configurations from TeamCity directly to the project you have open. In the old plugin, this had to be configured through VCS roots, which wasn’t an easy process.&lt;/p&gt;

&lt;p&gt;Now, users only need to create a given configuration once, and it will be saved in the source code. Everyone who downloads the project will then have it automatically configured and available without the need to set it up themselves.&lt;/p&gt;

&lt;h3&gt;Testing your local changes&lt;/h3&gt;

&lt;p&gt;One of the key benefits of the TeamCity IDEA plugins (both old and new) is the ability to run builds with your local changes before they are pushed to a remote branch, also known as a &lt;a href="https://www.jetbrains.com/help/teamcity/remote-run.html" rel="noopener noreferrer"&gt;remote run&lt;/a&gt;. This allows you to spot issues without breaking the build for everyone else on your team.&lt;/p&gt;

&lt;p&gt;Here’s how you can initiate a remote run from your IDE.&lt;/p&gt;

&lt;p&gt;1. Make some changes to your code.&lt;/p&gt;

&lt;p&gt;2. Go to &lt;em&gt;Tools | TeamCity (Experimental) | Remote Run…&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2kp9ugavti8nrf0ka7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2kp9ugavti8nrf0ka7p.png" alt=" " width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3. Then, under &lt;em&gt;Remote Run… | Settings…&lt;/em&gt;, click the target build configurations that you want to run with your local changes. The plugin will then remember your choice and run builds for the same configuration(s) on subsequent remote runs. You can configure these project-configuration relations in the plugin settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fteamcity-plugin-for-intellij-idea-remote-run-settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fteamcity-plugin-for-intellij-idea-remote-run-settings.png" alt="" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Link your projects to TeamCity build configurations&lt;/h3&gt;

&lt;p&gt;Setting up project-configuration relations allows you to explicitly choose which configurations should be triggered depending on the introduced changes.&lt;/p&gt;

&lt;p&gt;TeamCity’s IntelliJ IDEA integration enables you to choose the linking scope, selecting whether you want to link the whole project or only individual project modules to your TeamCity build configurations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fteamcity-plugin-for-intellij-idea-linking-scope.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fteamcity-plugin-for-intellij-idea-linking-scope.jpg" alt="" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1. Click &lt;em&gt;Tools | TeamCity (Experimental) | Settings…&lt;/em&gt; to open the plugin’s settings.&lt;/p&gt;

&lt;p&gt;2. Choose the required &lt;em&gt;Linking scope &lt;/em&gt;value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PROJECT – allows you to link the entire IntelliJ IDEA project to the target build configuration(s). This option works best when you need to trigger builds of the same configuration(s) regardless of which part of your code changed.&lt;/li&gt;



&lt;li&gt;MODULE – allows you to link individual &lt;a href="https://www.jetbrains.com/help/idea/creating-and-managing-modules.html" rel="noopener noreferrer"&gt;modules&lt;/a&gt; to corresponding build configurations. For example, you can run both &lt;em&gt;Build&lt;/em&gt; and &lt;em&gt;Test&lt;/em&gt; configurations if the main module of your application changes, and only the &lt;em&gt;Test&lt;/em&gt; configuration if you edit a separate module with unit and functional tests. This mode also benefits mono repositories where each module is a separate project with its own target build configuration(s).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Share your feedback&lt;/h2&gt;

&lt;p&gt;We’re still working on making the new plugin ready to replace the old one. For the time being, you can download both plugins – they won’t interfere with each other.&lt;/p&gt;

&lt;p&gt;Is there any functionality that you’d like us to add to the new plugin? Let us know in the comments below! We want to make the plugin as useful as possible, and your feedback can help us do exactly that.&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>teamcity</category>
      <category>intellijidea</category>
      <category>jetbrains</category>
    </item>
    <item>
      <title>Introducing the Unreal Engine Plugin for JetBrains TeamCity</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Tue, 14 May 2024 14:40:51 +0000</pubDate>
      <link>https://forem.com/teamcity/introducing-the-unreal-engine-plugin-for-jetbrains-teamcity-1im7</link>
      <guid>https://forem.com/teamcity/introducing-the-unreal-engine-plugin-for-jetbrains-teamcity-1im7</guid>
      <description>&lt;p&gt;TeamCity is a popular choice in game development for several reasons, including its support for Perforce, its ability to be installed on premises, and its numerous configuration options.
&lt;br&gt;&lt;br&gt;
In addition to its main application as a general-purpose CI/CD solution, we’re also striving to bring dedicated support for various&lt;a href="https://www.jetbrains.com/teamcity/integrations/build-tools/" rel="noopener noreferrer"&gt; build tools&lt;/a&gt;, too. Having already provided a Unity plugin for several years, we're now excited to officially introduce our &lt;a href="https://plugins.jetbrains.com/plugin/22679-unreal-engine-support" rel="noopener noreferrer"&gt;Unreal Engine Support plugin&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;We’ve been in close contact with several of our game development customers throughout the development of this new plugin to ensure it meets the needs of DevOps teams working on real-world Unreal Engine projects.&lt;/p&gt;

&lt;p&gt;Setting up a proper build pipeline for an Unreal Engine game can be a daunting task, especially for those with limited experience of the platform’s unique peculiarities. In this blog post, we'll walk you through a basic setup, while showcasing the plugin's features and demonstrating advanced capabilities such as distributed BuildGraph support.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fsample-build-pipeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fsample-build-pipeline.png" alt="" width="800" height="255"&gt;&lt;/a&gt;A sample build pipeline generated by the new Unreal Engine plugin&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Key features&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Here's a quick overview of what you can expect from this version of the plugin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A dedicated runner tailored for most common use cases (BuildCookRun, BuildGraph, and automation tests).&lt;/li&gt;



&lt;li&gt;Build distribution based on your BuildGraph description.&lt;/li&gt;



&lt;li&gt;On-the-fly automation test reporting.&lt;/li&gt;



&lt;li&gt;Automatic discovery of Unreal Engine installations on the build machines.&lt;/li&gt;



&lt;li&gt;Compatibility with the latest 5.x versions of Unreal Engine, plus support for 4.x.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;&lt;strong&gt;The demo&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;In this demo, we’ll be setting up a pipeline for two starter games shipped with Unreal:&lt;em&gt; Cropout&lt;/em&gt; and &lt;em&gt;Lyra&lt;/em&gt;. We’ll use AWS infrastructure (EC2 and FSx for OpenZFS) for build agents and TeamCity Cloud with the Unreal Engine plugin installed.&lt;/p&gt;

&lt;p&gt;We’ll look at two scenarios: when the engine is already installed on an agent and when it’s built from source along with the game. At the moment, TeamCity Cloud doesn’t offer agents with the preinstalled Unreal Engine, but you can always add your own&lt;a href="https://www.jetbrains.com/help/teamcity/cloud/install-and-start-teamcity-agents.html" rel="noopener noreferrer"&gt; self-hosted agent&lt;/a&gt; with all the required SDKs. This is the approach we’ll stick to in this blog post.&lt;/p&gt;

&lt;h2&gt;
&lt;strong&gt;Building &lt;/strong&gt;&lt;strong&gt;&lt;em&gt;Cropout&lt;/em&gt;&lt;/strong&gt;&lt;strong&gt; with BuildCookRun&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Building an Unreal project usually involves&lt;a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/build-operations-cooking-packaging-deploying-and-running-projects-in-unreal-engine" rel="noopener noreferrer"&gt; many steps&lt;/a&gt;, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compilation for the target platforms in the specified configurations.&lt;/li&gt;



&lt;li&gt;Asset cooking (converting all of the assets into ones that can be read on the target platforms).&lt;/li&gt;



&lt;li&gt;Packaging of the project into a proper distribution format.&lt;/li&gt;



&lt;li&gt;And many more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, of course, there’s the testing!&lt;/p&gt;

&lt;p&gt;To begin with, let’s start with a simple scenario and run all of these stages sequentially on a single machine utilizing the standard BuildCookRun command.&lt;/p&gt;

&lt;p&gt;For this scenario, we’ll use the latest vanilla Unreal Engine version available at the moment of writing, installed from EGL (Epic Games Launcher).&lt;/p&gt;

&lt;p&gt;After successfully connecting the agent to our TeamCity Cloud server, we can see it in the &lt;em&gt;Agents&lt;/em&gt; tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fteamcity-cloud-agents-pool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fteamcity-cloud-agents-pool.png" alt="" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, I’d like to take a moment to briefly explore some of the agent’s properties.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fagents-properties.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fagents-properties.png" alt="" width="800" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, looking at the picture above, we see that the agent discovered the engine and its version (we have more than one on our machine, as you can see). Keep a note of this information, as we’ll need it later for a build step configuration.&lt;/p&gt;

&lt;p&gt;Nowadays, the common approach is to store all your configs as code under source control (i.e. configuration as code). In TeamCity, you can do this using &lt;a href="https://www.jetbrains.com/teamcity/features/configuration-as-code/" rel="noopener noreferrer"&gt;Kotlin DSL&lt;/a&gt;. Of course, you can also go with the traditional UI configuration, but today, we’ll use the first approach (due to the popularity of YAML and the fact that it has become a de-facto standard, we’ve added it as a part of our recent release of&lt;a href="/?p=457320"&gt; TeamCity Pipelines –&lt;/a&gt; check it out if you haven’t already).&lt;/p&gt;

&lt;p&gt;The Kotlin DSL configuration for building&lt;em&gt; Cropout &lt;/em&gt;in TeamCity looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;unrealEngine {
    engineDetectionMode = automatic {
        identifier = "5.4"
    }
    command = buildCookRun {
        project = "cropout/CropoutSampleProject.uproject"
        buildConfiguration = standaloneGame {
            configurations = "Development+Shipping"
            platforms = "Mac"
        }
        cook = cookConfiguration {
            maps = "Village+MainMenu"
            cultures = "en"
            unversionedContent = true
        }
        stage = stageConfiguration {
            directory = "./staged"
        }
        archive = archiveConfiguration {
            directory = "./archived"
        }
        pak = true
        compressed = true
        prerequisites = true
    }
    additionalArguments = "-utf8output -buildmachine -unattended -noP4 -nosplash -stdout -NoCodeSign"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All of the settings are pretty self-descriptive, but there are a couple worth paying closer attention to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;engine detection mode&lt;/code&gt;&lt;br&gt;&lt;br&gt;Here, we can specify either “automatic” or “manual”. The former assumes you already have the engine installed on your agent and registered in the system.&lt;br&gt;
&lt;br&gt;Let me take this opportunity to clarify what “registered” means: Whenever you install the Unreal Engine from EGL or build it from source, it writes to certain files on the target machine (or registry in the case of Windows). More information on that can be found&lt;a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/installed-build-reference-guide-for-unreal-engine#registeringaninstalledbuild" rel="noopener noreferrer"&gt; here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This is essentially what the automatic detection mode is for. We read those files and publish identifiers as agent properties, so you can use them later to select the proper agent for your build.&lt;br&gt;&lt;br&gt;The “manual” mode allows you to set the exact path to the Unreal Engine root folder, which might be useful when you build from source. We'll touch on that later.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;build configuration&lt;/code&gt;&lt;br&gt;&lt;br&gt;By adjusting this parameter, we can specify the type of build we're creating, whether it's a standalone game, client, server, or both client and server components.&lt;br&gt;&lt;br&gt;Depending on the selected value, the plugin will apply &lt;code&gt;-client&lt;/code&gt;, &lt;code&gt;-server&lt;/code&gt;, &lt;code&gt;-noserver &lt;/code&gt;flags and manage &lt;code&gt;-clientconfig&lt;/code&gt;, &lt;code&gt;-serverconfig&lt;/code&gt;, &lt;code&gt;-config&lt;/code&gt;, &lt;code&gt;-targetplatform&lt;/code&gt;, and &lt;code&gt;-servertargetplatform&lt;/code&gt; parameters accordingly.&lt;/p&gt;

&lt;p&gt;So far, so good. Now, it’s time to add some automation tests and run the final pipeline.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;unrealEngine {
    engineDetectionMode = automatic {
        identifier = "5.4"
    }
    command = runAutomation {
        project = "cropout/CropoutSampleProject.uproject"
        execCommand = runTests {
            tests = """
                StartsWith:JsonConfig
                Input.Triggers.Released
            """.trimIndent()
        }
        nullRHI = true
    }
    additionalArguments = "-utf8output -buildmachine -unattended -noP4 -nosplash -stdout -NoCodeSign"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you may know, when working with the Unreal Engine Automation Framework, tests are usually executed using one of the following automation “subcommands”:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;RunAll&lt;/code&gt; – this is a pretty straightforward command that has the ability to run all required tests.&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;RunFilter &lt;/code&gt;– with this command, tests tagged with one of the specified filters (which includes such values as &lt;code&gt;Engine&lt;/code&gt;, &lt;code&gt;Stress&lt;/code&gt;, &lt;code&gt;Smoke&lt;/code&gt;, etc.) can be executed.&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;RunTests&lt;/code&gt; – this is the most versatile command, as it allows you to specify the list of tests to run (including prefix filters with &lt;code&gt;StartsWith&lt;/code&gt;, run group filters, and simple substring matches).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We tried to preserve the same wording in Kotlin DSL to keep it familiar for Unreal folks.&lt;/p&gt;

&lt;p&gt;It's also worth mentioning that the plugin parses the results of the tests on the fly and presents them in a nicely formatted manner native to TeamCity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fteamcity-test-results.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fteamcity-test-results.png" alt="" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s what the result of the build looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fbuild-results-teamcity.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fbuild-results-teamcity.png" alt="" width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below, we can see the game binaries published to the &lt;a href="https://www.jetbrains.com/help/teamcity/configuring-artifacts-storage.html" rel="noopener noreferrer"&gt;Artifacts Storage&lt;/a&gt;. By default, artifacts are published to &lt;a href="https://www.jetbrains.com/help/teamcity/configuring-artifacts-storage.html#Built-in+Artifacts+Storage" rel="noopener noreferrer"&gt;built-in storage&lt;/a&gt;; however, TeamCity also supports various&lt;a href="https://www.jetbrains.com/help/teamcity/configuring-artifacts-storage.html#external-artifacts-storage" rel="noopener noreferrer"&gt; external storage&lt;/a&gt; options. In the context of the cloud, it makes sense to configure publishing to S3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fexternal-storage-options-teamcity.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fexternal-storage-options-teamcity.png" alt="" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final configuration in the UI would then look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fui-configuration-option-step1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fui-configuration-option-step1.png" alt="" width="800" height="803"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here’s the step with the test run:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fui-configuration-option-step2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fui-configuration-option-step2.png" alt="" width="800" height="705"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the settings are disabled since we've enabled Kotlin DSL configuration and disabled editing it in the UI.&lt;/p&gt;

&lt;h2&gt;
&lt;strong&gt;Building &lt;/strong&gt;&lt;strong&gt;&lt;em&gt;Lyra&lt;/em&gt;&lt;/strong&gt;&lt;strong&gt; with BuildGraph&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We're slowly moving towards a more complex example with Lyra. Since it's a multiplayer game, let's build a Linux server (as we know that everything high-performance should be run on Linux!), along with Windows and Linux game clients.&lt;/p&gt;

&lt;p&gt;In the previous example, we ran all the steps sequentially on a single machine. Usually, this takes a significant amount of time. But there’s a better way, and it's called BuildGraph. This is Unreal's method for describing your build declaratively (or almost) as a set of tasks with dependencies among them. The different parts of the graph can then be executed together or split across different machines. The latter approach allows you to dramatically speed up the entire build process, especially for a big and complex project.&lt;/p&gt;

&lt;p&gt;The nice thing about BuildGraph is it manages all of the intermediate artifacts between jobs automatically. All you need is shared storage. While building &lt;em&gt;Lyra&lt;/em&gt;, we’ll be using this shared storage for two purposes: sharing data between nodes within a single build and maintaining a shared derived data cache (DDC).&lt;/p&gt;

&lt;p&gt;As we mentioned earlier, we’ll also build the engine from the source. There are multiple reasons why you might want to do that, but in our specific case, it’s because there’s no way to build a Linux server from the engine installed from EGL (at least at the time this post was written). This is due to the lack of files and SDKs provided with this particular engine version.&lt;/p&gt;

&lt;p&gt;Okay, that’s enough preamble – let’s get to grips with the code.&lt;/p&gt;

&lt;p&gt;The structure of the project and corresponding streams in Perforce look like this (we assume that you already have the Unreal Engine source code from Epic’s Perforce):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Flyra-perforce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Flyra-perforce.png" alt="" width="800" height="1072"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s the excerpt of the BuildGraph XML script that we’ll use for our build. This particular part of the script shows how we’ll build the editor along with the tools required for the compilation. It also contains a few tests, too. In our simple example, these are hardcoded. In a real-world scenario, you’d likely pass a list of tests to the script and employ more complicated logic.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;...
&amp;lt;!-- Editors --&amp;gt;
  &amp;lt;ForEach Name="Platform" Values="$(EditorPlatforms)" Separator="+"&amp;gt;
    &amp;lt;Property Name="Compiler" Value="$(AgentPrefixCompile)$(Platform)" /&amp;gt;

    &amp;lt;Agent Name="Build Editor and tools $(Platform)" Type="$(Compiler)"&amp;gt;
            
            ...

      &amp;lt;Property Name="ExtraToolCompileArguments" Value="$(ExtraToolCompileArguments) -architecture=arm64" If="'$(Platform)' == 'Mac'" /&amp;gt;
      
      &amp;lt;Node Name="$(ToolsNodeName) $(Platform)" Requires="Setup Toolchain $(Platform)" Produces="#$(Platform)ToolBinaries"&amp;gt;
        &amp;lt;Compile Target="CrashReportClient" Platform="$(Platform)" Configuration="Shipping" Arguments="$(ExtraToolCompileArguments)" Tag="#$(Platform)ToolBinaries"/&amp;gt;
        &amp;lt;Compile Target="CrashReportClientEditor" Platform="$(Platform)" Configuration="Shipping" Arguments="$(ExtraToolCompileArguments)" Tag="#$(Platform)ToolBinaries"/&amp;gt;
        &amp;lt;Compile Target="ShaderCompileWorker" Platform="$(Platform)" Configuration="Development" Arguments="$(ExtraToolCompileArguments)" Tag="#$(Platform)ToolBinaries"/&amp;gt;
        &amp;lt;Compile Target="UnrealLightmass" Platform="$(Platform)" Configuration="Development" Tag="#$(Platform)ToolBinaries"/&amp;gt;
        &amp;lt;Compile Target="InterchangeWorker" Platform="$(Platform)" Configuration="Development" Arguments="$(ExtraToolCompileArguments)" Tag="#$(Platform)ToolBinaries"/&amp;gt;
        &amp;lt;Compile Target="UnrealPak" Platform="$(Platform)" Configuration="Development" Arguments="$(ExtraToolCompileArguments)" Tag="#$(Platform)ToolBinaries"/&amp;gt;
        &amp;lt;Compile Target="BootstrapPackagedGame" Platform="$(Platform)" Configuration="Shipping" Arguments="$(ExtraToolCompileArguments)" Tag="#$(Platform)ToolBinaries" If="'$(Platform)' == 'Win64'"/&amp;gt;
      &amp;lt;/Node&amp;gt;
      
      ...
      
      &amp;lt;Node Name="$(EditorNodeName) $(Platform)" Requires="$(ToolsNodeName) $(Platform)" Produces="#$(Platform)EditorBinaries"&amp;gt;
        &amp;lt;Compile Target="$(ProjectName)Editor" Project="$(UProject)" Platform="$(Platform)" Configuration="Development" Arguments="$(ExtraEditorCompileArguments)" Tag="#$(Platform)EditorBinaries"/&amp;gt;
      &amp;lt;/Node&amp;gt;

            &amp;lt;Property Name="AutomationTestsNodeName" Value="Run Tests $(Platform)" /&amp;gt;
      &amp;lt;Node Name="$(AutomationTestsNodeName)" Requires="$(EditorNodeName) $(Platform)"&amp;gt;
        &amp;lt;Property Name="TestArgs" Value="-Project=$(UProject) -NullRHI -Deterministic" /&amp;gt;
        &amp;lt;Property Name="TestArgs" Value="$(TestArgs) -Test=UE.EditorAutomation -RunTest=&amp;amp;quot;StartsWith:Input&amp;amp;quot;" /&amp;gt;
        &amp;lt;Property Name="TestArgs" Value="$(TestArgs) -Build=Editor -UseEditor" /&amp;gt;
        &amp;lt;Command Name="RunUnreal" Arguments="$(TestArgs)" /&amp;gt;
      &amp;lt;/Node&amp;gt;
    &amp;lt;/Agent&amp;gt;

    &amp;lt;Property Name="BuildNodes" Value="$(BuildNodes);$(EditorNodeName) $(Platform);$(AutomationTestsNodeName);" /&amp;gt;
  &amp;lt;/ForEach&amp;gt;
  
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The full syntax is described in full on Epic’s website. Here, what we’re essentially doing is iterating over the list of platforms passed to the script via an option &lt;code&gt;EditorPlatforms&lt;/code&gt; and building the &lt;em&gt;Editor&lt;/em&gt; for each. One interesting feature of this part of the code is the &lt;code&gt;Type&lt;/code&gt; property of the agent node.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;Agent ... Type=""&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See this table from &lt;a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/buildgraph-script-elements-reference-for-unreal-engine#agent" rel="noopener noreferrer"&gt;the documentation&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2FScreenshot-2024-05-14-at-14.18.51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2FScreenshot-2024-05-14-at-14.18.51.png" alt="" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, in order to run a set of tasks on a particular agent, you can manipulate this field. At the time of writing, to make everything work, this part requires a little configuration of your build agents. Namely, you should define two properties in the&lt;a href="https://www.jetbrains.com/help/teamcity/configure-agent-installation.html" rel="noopener noreferrer"&gt; agent’s configuration file&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;unreal-engine.build-graph.agent.type&lt;/code&gt;: This could be any value (or a list of values separated by &lt;strong&gt;;&lt;/strong&gt;). The corresponding set of tasks will then be run only on an agent with at least one match.&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;unreal-engine.build-graph.agent.shared-dir&lt;/code&gt;: As discussed earlier, in order to run distributed BuildGraph builds, we need a shared storage location. With this property, we set a path to this storage location on a specific agent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what our setup for our EC2 build agents looks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For Linux:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;unreal-engine.build-graph.agent.type = CompileLinux;CookLinux;Linux
unreal-engine.build-graph.agent.shared-dir = /mnt/agent-shared-dir/intermediate
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;And for Windows (for some reason, mounting the folder as a separate drive caused one of the Windows system calls to fail, so we opted for a network share in the configuration):&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;unreal-engine.build-graph.agent.type = CompileWin64;CookWin64;Win64
unreal-engine.build-graph.agent.shared-dir = \\\\fs-040b8d6dab476baf1.fsx.eu-west-1.amazonaws.com\\fsx\\
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For real-world scenarios, it might make sense to differentiate between agents that perform cooking and those that perform compilation and ensure they have the appropriate specs.&lt;/p&gt;

&lt;p&gt;Let’s quickly take a look at what the processes of compilation, cooking and packaging of the game look like. In our script, we’ve separated the logic for building a client and building a server (as they differ in terms of passed flags):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;ForEach Name="Platform" Values="$(ClientPlatforms)" Separator="+"&amp;gt;
    &amp;lt;!-- COMPILATION --&amp;gt;
    &amp;lt;Property Name="Compiler" Value="$(AgentPrefixCompile)$(Platform)" /&amp;gt;
    &amp;lt;Agent Name="Compile $(Platform) Client" Type="$(Compiler)"&amp;gt;

      &amp;lt;Property Name="CompileNodeName" Value="Compile $(Platform) Client" /&amp;gt;  
      &amp;lt;Node Name="$(CompileNodeName)" Requires="$(ToolsNodeName) $(Platform)" Produces="#$(Platform) Client Binaries"&amp;gt;
        &amp;lt;ForEach Name="TargetConfiguration" Values="$(TargetConfigurations)" Separator="+"&amp;gt;    
          &amp;lt;Compile Target="$(ProjectName)Client" Project="$(UProject)" Platform="$(Platform)" Configuration="$(TargetConfiguration)" Arguments="$(ExtraProjectCompileArguments)" /&amp;gt;
        &amp;lt;/ForEach&amp;gt;
      &amp;lt;/Node&amp;gt;

      &amp;lt;Property Name="BuildNodes" Value="$(BuildNodes);$(CompileNodeName);" /&amp;gt;
    &amp;lt;/Agent&amp;gt;

    &amp;lt;!-- COOKING --&amp;gt;
    &amp;lt;Property Name="Cooker" Value="$(AgentPrefixCook)$(Platform)" /&amp;gt;

    &amp;lt;Property Name="CookPlatformNodeName" Value="Cook $(Platform) Client" /&amp;gt;
    &amp;lt;Agent Name="Cook $(Platform) Client" Type="$(Cooker)"&amp;gt;
      &amp;lt;Property Name="CookPlatform" Value="$(Platform)" /&amp;gt;
      &amp;lt;Property Name="CookPlatform" Value="Windows" If="'$(Platform)' == 'Win64'" /&amp;gt;

      &amp;lt;Node Name="$(CookPlatformNodeName)" Requires="$(EditorNodeName) $(Platform)" Produces="#Cook $(Platform) Client Complete"&amp;gt;
        &amp;lt;Cook Project="$(UProject)" Platform="$(CookPlatform)Client"/&amp;gt;
      &amp;lt;/Node&amp;gt;
    &amp;lt;/Agent&amp;gt;

    &amp;lt;Property Name="BuildNodes" Value="$(BuildNodes);$(CookPlatformNodeName);" /&amp;gt;

    &amp;lt;!-- PACKAGING --&amp;gt;
    &amp;lt;Agent Name="Package $(Platform) Client" Type="$(Platform)"&amp;gt;
      &amp;lt;Property Name="BCRArgs" Value="-Project='$(UProject)' -Platform=$(Platform) -NoCodeSign -Client" /&amp;gt;

        &amp;lt;!-- Stage --&amp;gt;
      &amp;lt;Node Name="Stage $(Platform) Client" Requires="Compile $(Platform) Client;Cook $(Platform) Client"&amp;gt;
        &amp;lt;ForEach Name="TargetConfiguration" Values="$(TargetConfigurations)" Separator="+"&amp;gt;
          &amp;lt;Command Name="BuildCookRun" Arguments="$(BCRArgs) -Configuration=$(TargetConfiguration) -SkipBuild -SkipCook -Stage -Pak" /&amp;gt;
        &amp;lt;/ForEach&amp;gt;
      &amp;lt;/Node&amp;gt;

      &amp;lt;!-- Package --&amp;gt;
      &amp;lt;Node Name="Package $(Platform) Client" Requires="Stage $(Platform) Client"&amp;gt;
        &amp;lt;ForEach Name="TargetConfiguration" Values="$(TargetConfigurations)" Separator="+"&amp;gt;    
          &amp;lt;Command Name="BuildCookRun" Arguments="$(BCRArgs) -Configuration=$(TargetConfiguration) -SkipBuild -SkipCook -SkipStage -Package" /&amp;gt;
        &amp;lt;/ForEach&amp;gt;
      &amp;lt;/Node&amp;gt;

      &amp;lt;!-- Publish (Packages) --&amp;gt;
      &amp;lt;Node Name="Archive $(Platform) Client" Requires="Package $(Platform) Client"&amp;gt;
        &amp;lt;ForEach Name="TargetConfiguration" Values="$(TargetConfigurations)" Separator="+"&amp;gt;    
          &amp;lt;Command Name="BuildCookRun" Arguments="$(BCRArgs) -Configuration=$(TargetConfiguration) -SkipBuild -SkipCook -SkipStage -SkipPak -SkipPackage -Archive" /&amp;gt;
        &amp;lt;/ForEach&amp;gt;
      &amp;lt;/Node&amp;gt;

      &amp;lt;Node Name="Publish $(Platform) Client" Requires="Archive $(Platform) Client"&amp;gt;
        &amp;lt;Property Name="PublishPlatform" Value="$(Platform)" /&amp;gt;
        &amp;lt;Property Name="PublishPlatform" Value="Windows" If="'$(Platform)' == 'Win64'" /&amp;gt;
        &amp;lt;Log Message="##teamcity[publishArtifacts 'game/ArchivedBuilds/$(PublishPlatform)Client=&amp;gt;$(PublishPlatform)Client.zip']" /&amp;gt;
      &amp;lt;/Node&amp;gt;
    &amp;lt;/Agent&amp;gt;

    &amp;lt;Property Name="BuildNodes" Value="$(BuildNodes);Archive $(Platform) Client;Publish $(Platform) Client" /&amp;gt;
  &amp;lt;/ForEach&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The script is pretty self-explanatory. We iterate over the list of platforms on which we want our client to run, which is again passed as an option. We compile for each of the platforms, cook the assets, and finally package everything. As the last step of the packaging process, we use a service message to publish the built client as a TeamCity build artifact.&lt;/p&gt;

&lt;p&gt;As you might have noticed, in this part of the script, we have three agents representing three stages of the build process (compilation, cooking, and packaging). The compilation requires tools belonging to the editor, but not the editor itself:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;Node Name="$(CompileNodeName)" Requires="$(ToolsNodeName) $(Platform)" Produces="#$(Platform) Client Binaries"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Meanwhile, the cooking process requires the actual editor:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;Node Name="$(CookPlatformNodeName)" Requires="$(EditorNodeName) $(Platform)" Produces="#Cook $(Platform) Client Complete"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And since there is no dependency between these two processes, they can run in parallel on different machines (if you have enough machines available). This simple example demonstrates the power of using BuildGraph: You simply describe pieces of work that share dependencies, and then they run simultaneously.&lt;/p&gt;

&lt;p&gt;In the interest of brevity, we won’t show the rest of the script that includes the server part, as it looks very similar to what we just described, with only the set of flags differing.&lt;/p&gt;

&lt;p&gt;Finally, we've reached the part with the plugin configuration in TeamCity. Since most of the work is described in the BuildGraph XML script, the DSL configuration is fairly brief:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;params {
    param("env.UE_SharedDataCachePath", "/mnt/agent-shared-dir/ddc")
    param("env.UE-SharedDataCachePath", "\\\\fs-040b8d6dab476baf1.fsx.eu-west-1.amazonaws.com\\fsx\\ddc")
}

steps {
    unrealEngine {
        id = "Unreal_Engine"
        name = "Build"
        engineDetectionMode = manual {
            rootDir = "engine"
        }
        command = buildGraph {
            script = "game/BuildProject.xml"
            targetNode = "BuildProject"
            options = """
                ProjectPath=%teamcity.build.checkoutDir%/game
                ProjectName=Lyra
                ClientPlatforms=Linux+Win64
                ServerPlatforms=Linux
                EditorPlatforms=Linux+Win64
                TargetConfigurations=Shipping
            """.trimIndent()
            mode = UnrealEngine.BuildGraphMode.Distributed
        }
        additionalArguments = "-utf8output -buildmachine -unattended -noP4 -nosplash -stdout -NoCodeSign"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we specify that we’d like to run the given BuildGraph script in distributed mode. Nevertheless, there’s always an option to run all the nodes sequentially on a single machine if we want to. We’ve also specified&lt;a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/using-derived-data-cache-in-unreal-engine#howtosetupasharedddc" rel="noopener noreferrer"&gt; a couple of environment variables&lt;/a&gt; that are required for the engine to enable the usage of a shared DDC. Those folders should already be mounted to the agents connected to TeamCity.&lt;/p&gt;

&lt;p&gt;Now, we can pass the following list of three platform options for our game: &lt;code&gt;ClientPlatforms&lt;/code&gt;, &lt;code&gt;ServerPlatforms&lt;/code&gt;, and &lt;code&gt;EditorPlatforms&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the UI, it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fbuild-step-unreal-engine.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fbuild-step-unreal-engine.png" alt="" width="800" height="749"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we launch the build, we get this build chain:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fbuild-chain-unreal-engine.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fbuild-chain-unreal-engine.png" alt="" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, as we can see, the plugin has transformed the graph into a proper TeamCity build chain.&lt;/p&gt;

&lt;p&gt;We can check the published artifacts on the corresponding tab of the specific build. Here's what it looks like for the Linux server:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Flinux-server-unreal-engine-teamcity-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F05%2Flinux-server-unreal-engine-teamcity-1.png" alt="" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before finishing up, we'd like to emphasize some important points to bear in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In order for the distribution process of BuildGraph to work, your build configuration should contain exactly one active build step.&lt;/li&gt;



&lt;li&gt;Currently, the plugin does not manage the retention period of the produced artifacts in the shared storage in any way. It's your responsibility to set it up properly.&lt;/li&gt;



&lt;li&gt;Examples in this blog post are by no means production-ready. Your real-world scenarios will likely be more complex. However, they could serve as a good starting point.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;&lt;strong&gt;Try it out!&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;You can get the demo code shown in this blog post from the&lt;a href="https://github.com/lesley29/unreal-teamcity-demo" rel="noopener noreferrer"&gt; GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’d like to try out the Unreal Engine plugin for TeamCity, you can download it from &lt;a href="https://plugins.jetbrains.com/plugin/22679-unreal-engine-support" rel="noopener noreferrer"&gt;JetBrains Marketplace&lt;/a&gt; and install it on a TeamCity On-Premises server.&lt;/p&gt;

&lt;p&gt;For TeamCity Cloud users, the Unreal Engine plugin has been pre-installed, allowing you to use it simply by adding an Unreal Engine build step. As a reminder, TeamCity Cloud agents don’t have Unreal Engine pre-installed, so you will need to use a self-hosted agent to run an Unreal Engine build.&lt;/p&gt;

&lt;p&gt;An important note for those who have been using a preview version of the plugin (any version that starts with 0.x.x): Please take into account that your existing configurations will be broken, as we have made changes and redesigned several features in the 1.0.0 version. You may need to recreate those configurations using the new version of the plugin.&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;What’s next?&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;First off, we’re looking forward to receiving your feedback. Please feel free to get in touch by submitting a ticket via our &lt;a href="https://youtrack.jetbrains.com/issues/TW" rel="noopener noreferrer"&gt;issue tracker&lt;/a&gt; or by commenting on this blog post.&lt;/p&gt;

&lt;p&gt;There are also some ideas we have in mind for further work, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Providing a more in-depth build log analysis.&lt;/li&gt;



&lt;li&gt;Including integration with UnrealGameSync (UGS), with features like build status publication and the potential provision of an out-of-the-box metadata server.&lt;/li&gt;



&lt;li&gt;Adding detection of the SDKs available on build machines, possibly using Turnkey.&lt;/li&gt;



&lt;li&gt;Looking into Gauntlet Automation Framework and what we can do there.&lt;/li&gt;



&lt;li&gt;Looking into how we can leverage recent advancements in the build process introduced by Epic Games, namely, checking out Unreal Build Accelerator (UBA) and coordinating it on the agents from TeamCity.&lt;/li&gt;



&lt;li&gt;Open-sourcing the plugin. We believe that this will increase transparency and allow for the creation of a better plugin overall. Furthermore, going open source can be a lot of fun.&lt;/li&gt;



&lt;li&gt;Anything else you can think of! If you have an idea of something that would be nice to have, please feel free to reach out via any of the channels we mentioned above or simply by leaving a comment on this blog post.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>teamcity</category>
      <category>gamedev</category>
      <category>unreal</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Make CI/CD Part of Your Development Flow With TeamCity Pipelines</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Mon, 18 Mar 2024 11:28:35 +0000</pubDate>
      <link>https://forem.com/teamcity/make-cicd-part-of-your-development-flow-with-teamcity-pipelines-c40</link>
      <guid>https://forem.com/teamcity/make-cicd-part-of-your-development-flow-with-teamcity-pipelines-c40</guid>
      <description>&lt;p&gt;&lt;a href="https://www.producthunt.com/posts/teamcity-pipelines-beta?utm_source=badge-featured&amp;amp;utm_medium=badge&amp;amp;utm_souce=badge-teamcity-pipelines-beta" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fapi.producthunt.com%2Fwidgets%2Fembed-image%2Fv1%2Ffeatured.svg%3Fpost_id%3D443136%26theme%3Dlight" alt="TeamCity Pipelines (beta) - Fall in love with CI/CD again | Product Hunt" width="250" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not many developers &lt;em&gt;love&lt;/em&gt; configuring their CI/CD pipelines. Describing jobs, defining job dependencies, debugging failed runs… If only there was an easier way to do it all!&lt;/p&gt;

&lt;p&gt;As the creators of TeamCity, a powerful and mature CI/CD tool that’s been around for over 17 years, we understand the struggle like no one else. Over the years, we’ve heard our customers praise TeamCity for how potent the tool is at handling pipelines of any complexity. Yet we also heard that the learning curve might be too steep for smaller teams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2Fimage2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2Fimage2.jpg" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s why we’re launching &lt;strong&gt;&lt;a href="https://jetbrains.com/teamcity/pipelines" rel="noopener noreferrer"&gt;TeamCity Pipelines&lt;/a&gt;&lt;/strong&gt;, a tool with a brand-new approach to CI/CD. TeamCity Pipelines reimagines the CI/CD process with its intuitive interface and smart configuration assistance, with JetBrains’ signature intelligence under the hood.&lt;/p&gt;

&lt;p&gt;TeamCity Pipelines is engineered to streamline your development flow, helping you accomplish tasks faster and run your CI/CD pipelines more efficiently.&lt;/p&gt;

&lt;p&gt;With TeamCity Pipelines, there’s no tradeoff between the simplicity of configuration and the powerful server capable of building complex pipelines.&lt;/p&gt;

&lt;p&gt;Let’s see what TeamCity Pipelines is about and how it can make your developers’ lives easier.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/2do8Mby92LI"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;Visual&lt;em&gt; Pipeline&lt;/em&gt; &lt;em&gt;Editor&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;In TeamCity Pipelines, we rethink the concept of pipeline configuration. Now, you can use YAML to configure your pipelines as code or take advantage of the visual&lt;em&gt; PipelineEditor&lt;/em&gt;. Here, you can easily define commands and dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2Fblog_visual-pipeline-editor.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2Fblog_visual-pipeline-editor.gif" alt="" width="1920" height="971"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Intelligent configuration assistance&lt;/h2&gt;

&lt;p&gt;TeamCity Pipelines will guide you through the pipeline configuration process, providing you with smart improvement suggestions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2FSlide-6_mvn-test.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2FSlide-6_mvn-test.gif" alt="" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For instance, TeamCity Pipelines can automatically detect specific build tools and suggest smart test parallelization options based on that, bringing you up to 75% faster runtime.&lt;/p&gt;

&lt;h2&gt;Run your pipelines in any environment&lt;/h2&gt;

&lt;p&gt;In TeamCity Pipelines, you can choose what type of agent you want to run your job on: Linux, Windows, or macOS.&lt;/p&gt;

&lt;p&gt;If your build requires extra tools, you can install them additionally on agents or run your jobs in a Docker container. TeamCity Pipelines features a built-in Docker image search and Dockerfile support.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2Fimage4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2Fimage4.gif" alt="" width="720" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Need to debug a failed build? Thanks to the &lt;em&gt;Open terminal&lt;/em&gt; feature, you can open the terminal and start debugging specific agent issues right from the TeamCity UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2FSlide-7_agent-terminal_short.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2FSlide-7_agent-terminal_short.gif" alt="" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Smart pipeline optimization&lt;/h2&gt;

&lt;p&gt;TeamCity Pipelines can also optimize your pipelines on the fly. Choose the option to reuse jobs, parallelize tests, or use build caches. A faster CI/CD experience has landed!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2FSmart-pipeline-optimization.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2FSmart-pipeline-optimization.png" alt="" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Configure pipelines as code with YAML&lt;/h2&gt;

&lt;p&gt;Complying with the industry standard, we offer TeamCity Pipelines users the opportunity to configure their pipelines as code by using YAML.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2FYAML.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F03%2FYAML.png" alt="" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can easily switch between the YAML and UI configurations.&lt;/p&gt;

&lt;p&gt;We hope that TeamCity Pipelines will prove to be a game-changer for your development process. Today, we’ve also launched it on &lt;a href="https://www.producthunt.com/products/jetbrains" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We’d really appreciate your support on this big day! If you feel like it, please support TeamCity Pipelines on Product Hunt and give us your valuable feedback.&lt;/p&gt;

&lt;p&gt;Yours truly,&lt;/p&gt;

&lt;p&gt;TeamCity Pipelines crew&lt;/p&gt;

</description>
      <category>teamcity</category>
      <category>cicd</category>
      <category>devops</category>
    </item>
    <item>
      <title>Configuration as Code for TeamCity Using Terraform</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Thu, 15 Feb 2024 11:06:05 +0000</pubDate>
      <link>https://forem.com/teamcity/configuration-as-code-for-teamcity-using-terraform-1ocf</link>
      <guid>https://forem.com/teamcity/configuration-as-code-for-teamcity-using-terraform-1ocf</guid>
      <description>&lt;p&gt;In DevOps, development and infrastructure tasks are split. Developers and build engineers handle project configuration and scripting, while DevOps engineers on the infrastructure side manage things like TeamCity instances, database maintenance, and permissions. &lt;/p&gt;

&lt;p&gt;Although &lt;a href="https://www.jetbrains.com/teamcity/features/configuration-as-code/" rel="noopener noreferrer"&gt;the Kotlin DSL&lt;/a&gt; can address CI/CD needs at the project level, it lacks system administration capabilities. It is incapable of setting universal server configurations and managing users, which poses challenges for DevOps engineers, especially those from a systems administration background.&lt;/p&gt;

&lt;p&gt;To overcome this, TeamCity has introduced the &lt;a href="https://github.com/JetBrains/terraform-provider-teamcity" rel="noopener noreferrer"&gt;Terraform Provider for TeamCity&lt;/a&gt; on the basis of this widely adopted infrastructure provisioning tool. The Terraform Provider uses a language familiar to DevOps professionals and streamlines global server setup, user management, permissions, and project initiation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-us.googleusercontent.com%2FgdQNRKSlYbrFhp2YkUnF7woP1iNAQ0oWcMdFnxySYA8Q3kPdyuU10B8LudKp_-eUkWRTqw3gjrgpvLAOBvmWCVVNf_hhVCzqdHwM5oOZGBQnEM6riZm2Nx7h4veOi7C3Wh0xDO4UmD_KFz3tsQC0gzA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-us.googleusercontent.com%2FgdQNRKSlYbrFhp2YkUnF7woP1iNAQ0oWcMdFnxySYA8Q3kPdyuU10B8LudKp_-eUkWRTqw3gjrgpvLAOBvmWCVVNf_hhVCzqdHwM5oOZGBQnEM6riZm2Nx7h4veOi7C3Wh0xDO4UmD_KFz3tsQC0gzA" width="1600" height="927"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://www.jetbrains.com/lp/devecosystem-2023/devops/#devops_infr_provisioning_devops" rel="noopener noreferrer"&gt;Developer Ecosystem Report 2023&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Terraform Provider in action: Setting up OAuth for GitHub accounts&lt;/h2&gt;

&lt;p&gt;Let’s see how we can use the new Terraform Provider for TeamCity. In the first example, we’ll set up OAuth for GitHub accounts. Here, we need to change the server URL and then add a GitHub App authentication model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTeamCity-and-Terraform-Provider_1-2-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTeamCity-and-Terraform-Provider_1-2-1.png" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTeamCity-and-Terraform-Provider_2-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTeamCity-and-Terraform-Provider_2-1.png" alt="" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Terraform, we can describe our web forms as a set of resources. For the global settings, we can change the server URL. All of the other settings are left as default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity_3-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity_3-1.png" alt="" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, we add a module for authentication as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-authentication-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-authentication-1.png" alt="" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also need to add a connection with our custom GitHub App into our root project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-GH-connection-2-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-GH-connection-2-1.png" alt="" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also configure SMTP settings for notifications, add license keys, and set up cleaning. &lt;/p&gt;

&lt;p&gt;Terraform is a command line tool. Here, we can type in &lt;code&gt;terraform apply&lt;/code&gt;, and it will evaluate our configuration files and declare which changes will be made in our infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-apply-command.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-apply-command.png" alt="" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the changes are applied, we can log in to TeamCity with a new external account.&lt;/p&gt;

&lt;h2&gt;Creating accounts and granting permissions in advance&lt;/h2&gt;

&lt;p&gt;In TeamCity, you can create custom roles and grant only certain permissions to certain roles, following the principle of least privilege. Let’s see how to do so using Terraform Provider.&lt;/p&gt;

&lt;p&gt;Let’s create a new custom role, a project, and a new group, and assign project permissions to the group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-custom-role-2-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-custom-role-2-1.png" alt="" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the user connects to TeamCity for the first time, they’ll immediately have access to their projects and custom permissions.&lt;/p&gt;

&lt;p&gt;The project that we created is empty. However, when you start developing a new product or microservice, it’s great to provide the team with a working example. Here, we have a repo in GitHub with a basic Kotlin DSL script.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fgithub-repo-terraform-provider.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fgithub-repo-terraform-provider.png" alt="" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s register it in TeamCity. We’ll create a project, and within it, register an SSH key and create a VCS root using SSH authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-ssh-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-ssh-key.png" alt="" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also enable versioned settings there to ensure our Kotlin DSL script is applied.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-versioned-settings-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-versioned-settings-1.png" alt="" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Managing GitHub resources via Terraform&lt;/h2&gt;

&lt;p&gt;Terraform doesn’t just refer to GitHub resources but actually manages them. To demonstrate how this feature works, let's create a new repo by cloning it from a template.&lt;/p&gt;

&lt;p&gt;In the code, we declare a new GitHub repository and refer to our template as a base for cloning.&lt;/p&gt;

&lt;p&gt;This integration can also work the other way around. Namely, Terraform can also reflect changes in your actual infrastructure. Now, let’s see how we can create a repo manually.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-clone-repo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-clone-repo.png" alt="" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we’ve listed all of the repos in their organization and ensured that each of them has a corresponding set of TeamCity resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-each-key-2-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2FTerraform-Provider-for-TeamCity-each-key-2-1.png" alt="" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, Terraform was able to find a new repo that we recently created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-picked-up-repo-2800x1546.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-picked-up-repo-2800x1546.png" alt="" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also add a set of TeamCity objects, and they will appear automatically in the corresponding TeamCity project.&lt;/p&gt;

&lt;h2&gt;Importing existing resources&lt;/h2&gt;

&lt;p&gt;For those who have been working with TeamCity for a while, there is a way to import existing configurations and settings into Terraform without recreating everything from scratch. Here’s an example of how we can customize existing settings.&lt;/p&gt;

&lt;p&gt;Here, we’ve specified the ID of a TeamCity object and the ID of a resultant Terraform resource:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-ID-specified-2800x1552.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-for-teamcity-ID-specified-2800x1552.png" alt="" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we can tell Terraform to go into an actual TeamCity instance, read its state, and generate configuration files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-import-existing-role.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-import-existing-role.png" alt="" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Terraform will then fetch the list of permissions from TeamCity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-fetched-roles-from-teamcity.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jetbrains.com%2Fwp-content%2Fuploads%2F2024%2F02%2Fterraform-provider-fetched-roles-from-teamcity.png" alt="" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can then go ahead and add a new permission in Terraform. It will then automatically appear in TeamCity.&lt;/p&gt;

&lt;h2&gt;Learn more about Terraform Provider for TeamCity&lt;/h2&gt;

&lt;p&gt;You can find the &lt;a href="https://registry.terraform.io/providers/JetBrains/teamcity/latest/docs" rel="noopener noreferrer"&gt;Terraform Provider for TeamCity&lt;/a&gt; in the HashiCorp Terraform registry. Please refer to &lt;a href="https://registry.terraform.io/providers/JetBrains/teamcity/latest/docs" rel="noopener noreferrer"&gt;the documentation &lt;/a&gt;for more resources and details. &lt;/p&gt;

&lt;p&gt;Also, make sure to check out the project’s &lt;a href="https://github.com/JetBrains/terraform-provider-teamcity" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to &lt;a href="https://www.jetbrains.com/teamcity/get-in-touch/" rel="noopener noreferrer"&gt;reach out to us&lt;/a&gt; – we’ll be happy to help.&lt;/p&gt;

</description>
      <category>teamcity</category>
      <category>devops</category>
      <category>infrastructureascode</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Kotlin DSL Examples in TeamCity</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Fri, 08 Sep 2023 15:24:25 +0000</pubDate>
      <link>https://forem.com/teamcity/kotlin-dsl-examples-in-teamcity-3n24</link>
      <guid>https://forem.com/teamcity/kotlin-dsl-examples-in-teamcity-3n24</guid>
      <description>&lt;p&gt;TeamCity offers the ability to define project settings and &lt;a href="https://www.jetbrains.com/teamcity/features/configuration-as-code/?_gl=1*lflsmt*_ga*MTk1MDA2NTY0LjE2OTM1NjkxMzA.*_ga_9J976DJZ68*MTY5NDE4NTQ3Ny4yNTYuMS4xNjk0MTg1NjUyLjYwLjAuMA..&amp;amp;_ga=2.264310726.8966633.1693814089-195006564.1693569130" rel="noopener noreferrer"&gt;configure CI/CD pipelines programmatically&lt;/a&gt; with the help of the Kotlin DSL. &lt;/p&gt;

&lt;p&gt;To help you take advantage of the Kotlin DSL’s capabilities and simplify the build configuration process, we’ve created extensive Kotlin DSL documentation. It comes with examples that you can simply copy-paste directly into your code base.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qcf771jhav4ybur05vr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qcf771jhav4ybur05vr.png" alt="Kotlin DSL examples" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Kotlin DSL documentation works
&lt;/h2&gt;

&lt;p&gt;Every TeamCity server has its own Kotlin DSL documentation, which is automatically curated to match the TeamCity version and any plugins installed on the server. If you install a new plugin, the documentation compiles again, providing you with relevant examples.&lt;/p&gt;

&lt;p&gt;You can also refer to the general Kotlin DSL documentation, which is available in &lt;a href="https://www.jetbrains.com/help/teamcity/kotlin-dsl-documentation/index.html?_gl=1*1ngkdxf*_ga*MTk1MDA2NTY0LjE2OTM1NjkxMzA.*_ga_9J976DJZ68*MTY5NDE4NTQ3Ny4yNTYuMS4xNjk0MTg1ODA0LjYwLjAuMA..&amp;amp;_ga=2.269018168.8966633.1693814089-195006564.1693569130" rel="noopener noreferrer"&gt;the TeamCity docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessing the Kotlin DSL documentation from IntelliJ IDEA
&lt;/h2&gt;

&lt;p&gt;The Kotlin DSL documentation is available right from IntelliJ IDEA (both Ultimate and Community editions). You can access it by going to &lt;strong&gt;Maven Tool Window | Download Sources and Documentation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpcfjhtp3qva1p1ef1rf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpcfjhtp3qva1p1ef1rf.png" alt="Kotlin DSL in TeamCity" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another way to access the Kotlin DSL documentation directly from your IDE is to run the &lt;code&gt;mvn -U dependency:sources&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;The documentation’s context and examples change when you click on an entity (for example, a build step or a trigger). The information is displayed either in a popup window or in the panel on the left, depending on the settings you’ve selected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88ukxsuaokeq3jphowng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88ukxsuaokeq3jphowng.png" alt="Kotlin DSL" width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a few different ways to open the Kotlin DSL examples from your IDE:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pressing &lt;code&gt;F1&lt;/code&gt; on Mac or &lt;code&gt;Ctrl + Q&lt;/code&gt; on Windows. Refer to &lt;a href="https://www.jetbrains.com/help/idea/viewing-reference-information.html?keymap=windows&amp;amp;_gl=1*o4xs22*_ga*MTk1MDA2NTY0LjE2OTM1NjkxMzA.*_ga_9J976DJZ68*MTY5NDE4NTQ3Ny4yNTYuMS4xNjk0MTg1OTQ5LjYwLjAuMA..&amp;amp;_ga=2.8405116.8966633.1693814089-195006564.1693569130#keep-docs-in-tool-window" rel="noopener noreferrer"&gt;this section&lt;/a&gt; of the IntelliJ IDEA documentation for more details.&lt;/li&gt;
&lt;li&gt;Clicking on the name of an entity (such as a build step or a command). The examples will open in the menu on the right-hand side of the window.&lt;/li&gt;
&lt;li&gt;Simply hovering over an entity to access the in-line information window.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhta6fvgqh2p4t9wx2omv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhta6fvgqh2p4t9wx2omv.png" alt="Kotlin DSL" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How this feature is helpful
&lt;/h2&gt;

&lt;p&gt;Using Kotlin DSL examples can save you time when configuring your pipelines as code. The examples also make it easier to discover all of the things you can do when configuring builds, in addition to helping you identify the scenarios that TeamCity can support.&lt;/p&gt;

&lt;p&gt;Working with the Kotlin DSL examples can be a particularly great option when you are just getting started, as they provide a solid foundation on which to build your understanding of the Kotlin DSL.&lt;/p&gt;

&lt;p&gt;TeamCity also provides you with an option to view your settings as code with the help of the &lt;strong&gt;View as code&lt;/strong&gt; button, which is available on the build level. This displays your settings as code that you can copy and paste to your codebase.&lt;/p&gt;

&lt;p&gt;If your project can’t be configured via the UI and you’d still like to experiment with the View as code feature, consider setting up a sandbox project on your TeamCity server. It will give you a chance to play around with different TeamCity features and see how they look in the Kotlin DSL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further resources
&lt;/h2&gt;

&lt;p&gt;If you’d like to learn more about using the Kotlin DSL for TeamCity, here are some additional resources that you might find useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Video series “&lt;a href="https://youtu.be/Mxa-eHMe2w8" rel="noopener noreferrer"&gt;Kotlin DSL: From Zero to Hero&lt;/a&gt;”&lt;/li&gt;
&lt;li&gt;Blog post “&lt;a href="https://blog.jetbrains.com/teamcity/2021/04/kotlin-dsl-for-beginners-recommended-refactorings/" rel="noopener noreferrer"&gt;Kotlin DSL for Beginners: Recommended Refactorings&lt;/a&gt;”&lt;/li&gt;
&lt;li&gt;Blog post “&lt;a href="https://blog.jetbrains.com/teamcity/2020/09/creating-teamcity-project-templates-with-kotlin-dsl-context-parameters/" rel="noopener noreferrer"&gt;Creating TeamCity Project Templates with Kotlin DSL Context Parameters&lt;/a&gt;”&lt;/li&gt;
&lt;li&gt;Blog post series “&lt;a href="https://blog.jetbrains.com/teamcity/2019/03/configuration-as-code-part-1-getting-started-with-kotlin-dsl/" rel="noopener noreferrer"&gt;Configuration as Code&lt;/a&gt;”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Over to you
&lt;/h2&gt;

&lt;p&gt;Do you have any questions or comments about how we can improve the Kotlin DSL examples and documentation for TeamCity? We’d love to get your feedback! Feel free to share it in the comment section below. &lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>How to Use the Space Git Flow With TeamCity</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Thu, 27 Apr 2023 15:44:45 +0000</pubDate>
      <link>https://forem.com/teamcity/how-to-use-the-space-git-flow-with-teamcity-22hp</link>
      <guid>https://forem.com/teamcity/how-to-use-the-space-git-flow-with-teamcity-22hp</guid>
      <description>&lt;p&gt;Do you use feature branches or Git flow to ensure code quality?&lt;/p&gt;

&lt;p&gt;The powerful combination of JetBrains Space Git flow with TeamCity offers a complete solution to help you achieve better code quality and keep your main branch green with stable builds. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6o6xkig27qyo4dlcmgmj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6o6xkig27qyo4dlcmgmj.png" alt=" " width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/space/?_ga=2.35286884.416760693.1682323121-1928317243.1667914633&amp;amp;_gl=1*114w577*_ga*MTkyODMxNzI0My4xNjY3OTE0NjMz*_ga_9J976DJZ68*MTY4MjYwMzk4NC4xODAuMS4xNjgyNjA5NzU1LjIzLjAuMA.." rel="noopener noreferrer"&gt;Space&lt;/a&gt; provides you with Git hosting, code reviews, and quality gates, while &lt;a href="https://www.jetbrains.com/teamcity" rel="noopener noreferrer"&gt;TeamCity&lt;/a&gt; offers a build pipeline. The native integration between tools will save you time and effort by ensuring you have a complete and well-integrated flow with a unified UI. &lt;/p&gt;

&lt;p&gt;Adopting the Space Git flow with TeamCity is easy and allows you to keep your main branch stable while controlling changes automatically. &lt;/p&gt;

&lt;p&gt;In this blog post, we’ll introduce the combo of the Space Git flow and TeamCity, and guide you through the process of using it in your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Space Git Flow, and Why Use it?
&lt;/h2&gt;

&lt;p&gt;The Space Git flow is a branching strategy that is similar to GitHub flow, but with a greater emphasis on safety when introducing changes to the main branch and the ability to scale to large projects and teams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fly3j3qguayhnwq0t0bl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fly3j3qguayhnwq0t0bl4.png" alt=" " width="800" height="661"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Getting started with the Space Git flow is easy and doesn’t require going all-in, as you can mirror your existing Git repository without having to migrate, and you can switch back any time.&lt;/p&gt;

&lt;p&gt;Using the Space Git flow integrated with TeamCity allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Achieve higher-quality code and a stable main branch by configuring quality gates based on TeamCity build status for merge requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Introduce a code review process your team will love, integrated with IntelliJ IDEA and available on the go with Space iOS and Android apps.&lt;br&gt;
&lt;a href="https://blog.jetbrains.com/space/2023/04/18/space-git-flow/" rel="noopener noreferrer"&gt;Read this article&lt;/a&gt; to learn more about the Space Git flow.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Use the Space Git Flow With TeamCity
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mirror or host your Git repository in Space&lt;/strong&gt;&lt;br&gt;
Start by creating bi-directional mirrors of your repository from GitHub or another Git service and link it to Space in a few clicks. &lt;/p&gt;

&lt;p&gt;You can also use Space to host your source code privately. If you host it in Space, you can take advantage of the web-based interface and JetBrains IDE integration for a seamless development experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protect your main branch from accidental pushes
&lt;/h3&gt;

&lt;p&gt;To prevent accidental pushes to the main branch, you can set up branch protection in Space. This helps you protect repositories from unauthenticated commits, restrict who can push or merge changes into the branch, and prevent accidental branch deletion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6ju5rc5vy8g6m4q3nk0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6ju5rc5vy8g6m4q3nk0.png" alt=" " width="800" height="777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve set up branch protection, the only way a change can make it to main is through a merge request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a feature branch
&lt;/h3&gt;

&lt;p&gt;To start working on a new feature, you’ll need to either clone the repository to your machine, or use &lt;a href="https://blog.jetbrains.com/space/2021/11/29/introducing-remote-development-with-space/" rel="noopener noreferrer"&gt;remote development&lt;/a&gt; with the IDE hosted on a virtual machine in the Space cloud.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2weard7x13kyjp0gp0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2weard7x13kyjp0gp0u.png" alt=" " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the Space Git flow, you make changes in a separate feature branch and then request a code review before merging it back to main. From your IDE, you can make changes, add a commit message, and then push this branch back to Space. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7clyls6i6iyj3d3tme1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7clyls6i6iyj3d3tme1.png" alt=" " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a merge request
&lt;/h3&gt;

&lt;p&gt;Create a merge request to begin the process of moving your new code into main. You can do this from within your IDE using the native integration, or you can find your branch in Space and create a merge request from there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrwvjqdzwk2ra86d64o8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrwvjqdzwk2ra86d64o8.png" alt=" " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can create a title and description for your merge request and see the commits that will be part of it. The quality gates configured in Space require at least one person to review these changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd72rnanriv221sczh85z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd72rnanriv221sczh85z.png" alt=" " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/help/space/branch-and-merge-restrictions.html?_ga=2.224707423.416760693.1682323121-1928317243.1667914633&amp;amp;_gl=1*25a72i*_ga*MTkyODMxNzI0My4xNjY3OTE0NjMz*_ga_9J976DJZ68*MTY4MjYwMzk4NC4xODAuMS4xNjgyNjA5NDc3LjYwLjAuMA..#quality-gates-for-merge-requests" rel="noopener noreferrer"&gt;Quality gates&lt;/a&gt; are a mandatory and customizable set of conditions that need to be fulfilled before merging. Apart from code reviewer’s approval, you can set up a Space Automation job and a TeamCity check as gates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Space will require a review based on code ownership**
&lt;/h3&gt;

&lt;p&gt;In your repository, you can create a special file named CODEOWNERS that specifies who is responsible for specific folders and files. Later, you and your colleagues will have the option to select a code owner to review your changes as a part of quality gates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wait for your team to review the changes **
&lt;/h3&gt;

&lt;p&gt;Now you wait for your colleagues to review the changes. They can add comments and suggestions, or they can simply approve the request. With turn-based code reviews, Space makes it easy for both the author and the reviewer to understand whose turn it is to take action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrr4yi3fv6iwd1c8248d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrr4yi3fv6iwd1c8248d.png" alt=" " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Space allows you to collect your comments as drafts and send them in batches so as not to overload your colleagues with unnecessary notifications.  &lt;/p&gt;

&lt;p&gt;After you’ve agreed on changes with your reviewer, you can proceed with merging them.&lt;/p&gt;

&lt;p&gt;Ensure your build is green &lt;br&gt;
With Space and TeamCity, there are a few options that you can use to make sure your build is green before merging your changes. You can use either or both of them for extra security.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run CI/CD checks
&lt;/h3&gt;

&lt;p&gt;After you create a merge request, Space Automation and/or TeamCity CI jobs are triggered to validate the changes by building the code and running tests. As part of quality gates, the changes will be merged into main only if a CI/CD server can successfully build the feature branch. &lt;/p&gt;

&lt;p&gt;The checks can be set and completed by both Space Automation and TeamCity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzldw4qn3f7uknsz0ey6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzldw4qn3f7uknsz0ey6b.png" alt=" " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These checks, however, only ensure the new code is valid and integrates well with the main branch at the time of branching. With Safe Merge, validation is done by attempting to integrate the new code with the very latest code from the main branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run Safe Merge
&lt;/h3&gt;

&lt;p&gt;You can use Safe Merge before merging the changes directly into main. Safe Merge acts like a time machine – it runs a preview of what your main branch would look like with the changes. &lt;/p&gt;

&lt;p&gt;This can be especially useful for large projects because while you were working on a feature branch, the main branch could have received changes that conflict with your work. Safe Merge allows you to catch these conflicts before actually merging the branches.&lt;/p&gt;

&lt;p&gt;Space creates a temporary commit with the latest changes, which can then be used to perform the required quality checks using an Automation job or TeamCity build.&lt;/p&gt;

&lt;p&gt;In TeamCity, you’ll see Space trigger a special build, and TeamCity will report the build status back to Space when it’s finished. The changes are merged into the main branch only if the build succeeds. Otherwise, the merge is rejected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5iwabyft2r2gxn1wgon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5iwabyft2r2gxn1wgon.png" alt=" " width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cicd</category>
    </item>
    <item>
      <title>Transition to Native Git in TeamCity Brings 10x Fetch Time Reduction to IntelliJ IDEA</title>
      <dc:creator>JetBrains TeamCity</dc:creator>
      <pubDate>Tue, 12 Jul 2022 15:13:03 +0000</pubDate>
      <link>https://forem.com/teamcity/transition-to-native-git-in-teamcity-brings-10x-fetch-time-reduction-to-intellij-4fde</link>
      <guid>https://forem.com/teamcity/transition-to-native-git-in-teamcity-brings-10x-fetch-time-reduction-to-intellij-4fde</guid>
      <description>&lt;p&gt;Starting from &lt;a href="https://blog.jetbrains.com/teamcity/tag/2022-04/" rel="noopener noreferrer"&gt;version 2022.04&lt;/a&gt;, TeamCity switched to native Git on the server side for Git VCS connections. The switch should positively impact both performance and overall experience of working with Git repositories on the TeamCity server side.&lt;/p&gt;

&lt;p&gt;In this blog post, we’ll talk about the reasons for the switch and our own experience with this feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;In the case of the agent-side checkout, TeamCity agents have always been using a native Git executable to checkout sources. This functionality spawns a separate process for native Git commands like &lt;em&gt;ls-remote, fetch, checkout&lt;/em&gt;, and others, so it requires the Git executable to be present on the agent. When it comes to SSH communication and depending on the configuration, native Git may use the &lt;a href="https://www.openssh.com/" rel="noopener noreferrer"&gt;OpenSSH&lt;/a&gt;, &lt;a href="https://www.putty.org/" rel="noopener noreferrer"&gt;PuTTY&lt;/a&gt;, or &lt;a href="http://www.jcraft.com/jsch/" rel="noopener noreferrer"&gt;JCraft JSch&lt;/a&gt; Java library as the SSH client.&lt;/p&gt;

&lt;p&gt;Meanwhile, the TeamCity server also requires a copy of a Git repository to detect newly pushed commits. These newly found commits later pop up as pending and are included in the following builds. In a regular scenario on the server side, TeamCity first checks if the local repository has the same state (a set of branches pointing to a set of commits) as the remote one. If the local state is out-of-date, missing commits should be obtained from the remote.&lt;/p&gt;

&lt;p&gt;In terms of Git, TeamCity server performs an &lt;em&gt;ls-remote&lt;/em&gt; operation possibly followed by a &lt;em&gt;fetch&lt;/em&gt;. There is also some other server-side functionality which works with remote repositories, like &lt;a href="https://www.jetbrains.com/help/teamcity/vcs-labeling.html?_gl=1*wkv2vm*_ga*MTQ0MDU0NzAxNS4xNjI2OTYxMjU2*_ga_9J976DJZ68*MTY1NzYzNjEyMy4xMjUuMS4xNjU3NjM4MDk0LjA.&amp;amp;_ga=2.82146974.985314392.1657526832-1440547015.1626961256" rel="noopener noreferrer"&gt;VCS labeling feature&lt;/a&gt; that creates Git tags, or &lt;a href="https://www.jetbrains.com/help/teamcity/storing-project-settings-in-version-control.html?_gl=1*wkv2vm*_ga*MTQ0MDU0NzAxNS4xNjI2OTYxMjU2*_ga_9J976DJZ68*MTY1NzYzNjEyMy4xMjUuMS4xNjU3NjM4MDk0LjA.&amp;amp;_ga=2.82146974.985314392.1657526832-1440547015.1626961256" rel="noopener noreferrer"&gt;versions settings&lt;/a&gt; that can push commits to the remote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach with Eclipse JGit and JCraft JSch
&lt;/h2&gt;

&lt;p&gt;Historically, to work with both local and remote repositories on the TeamCity server-side, we chose the Eclipse JGit Java library. For SSH transport and operations with SSH keys, we used the JCraft JSch Java library. Both JGit and JSch libraries did a very good job. However, they have some performance, memory-related, and other limiting issues.&lt;/p&gt;

&lt;p&gt;Among the main concerns and complaints were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow fetch for large repositories, which could drag out the overall process of checking for changes on the TeamCity server.&lt;/li&gt;
&lt;li&gt;Memory issues when performing fetch inside the TeamCity process, which required more complicated out-of-process solutions.&lt;/li&gt;
&lt;li&gt;Notable delay between creating a branch in a Git repository and the moment when TeamCity detects it and starts showing it in the branch list for a build configuration, providing the ability to start a build in the new branch. &lt;/li&gt;
&lt;li&gt;Inability to receive a pack file with any object larger than 2GB, which requires switching the whole repository to Git LFS.&lt;/li&gt;
&lt;li&gt;Besides, it was often problematic to compare errors reported by the mentioned libraries with messages coming from native Git under the same conditions. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, the official JCraft JSch library is no longer maintained and consequently does not support modern secure algorithms and ciphers. Although &lt;a href="https://github.com/mwiede/jsch" rel="noopener noreferrer"&gt;an actively developed fork&lt;/a&gt; has become available recently, we decided to use the native Git approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native Git approach
&lt;/h2&gt;

&lt;p&gt;These issues brought about the idea of trying native Git with OpenSSH for SSH transport on the TeamCity server side (as we said before, agents have already been using native Git). After a significant amount of work which took a few months, we were finally able to test the native Git approach internally, and the results were better than we had expected.&lt;/p&gt;

&lt;p&gt;Our current solution is to use a hybrid approach. For convenience we’re using Eclipse JGit while working with local repositories, e.g. iterating over commits history in the local repository, when collecting modified files, their content, etc. But when it comes to remote communication, such as obtaining a current remote repository state, TeamCity server spawns a process with native Git executable instead of running a JGit inside a Java process.&lt;/p&gt;

&lt;h2&gt;
  
  
  JetBrains successful experience
&lt;/h2&gt;

&lt;p&gt;As you might know, we in JetBrains dogfood our products as much as possible. Our internal TeamCity server, which builds most of JetBrains products, currently has more than 3,000 VCS roots (mainly Git). Among the biggest Git repositories which are checked out on our TeamCity server is, of course, the IntelliJ Platform hosted by &lt;a href="https://www.jetbrains.com/space/?_gl=1*1dda298*_ga*MTQ0MDU0NzAxNS4xNjI2OTYxMjU2*_ga_9J976DJZ68*MTY1NzYzNjEyMy4xMjUuMS4xNjU3NjM4MDk0LjA.&amp;amp;_ga=2.111900172.985314392.1657526832-1440547015.1626961256" rel="noopener noreferrer"&gt;JetBrains Space&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Switching to native Git together with a few other related &lt;a href="https://www.jetbrains.com/help/teamcity/teamcity-2022-04-release-notes.html?_gl=1*1dda298*_ga*MTQ0MDU0NzAxNS4xNjI2OTYxMjU2*_ga_9J976DJZ68*MTY1NzYzNjEyMy4xMjUuMS4xNjU3NjM4MDk0LjA.&amp;amp;_ga=2.111900172.985314392.1657526832-1440547015.1626961256" rel="noopener noreferrer"&gt;fixes in 2022.04&lt;/a&gt; solved all the above-mentioned problems on our internal TeamCity server and also showed an impressive fetch time reduction for our Linux node, which is responsible for VCS operations.&lt;/p&gt;

&lt;p&gt;The following image shows statistics for the fetch time for IntelliJ Platform repository collected during the time slot covering the switch from JGit to native Git. The fetch time decreased by almost 10 times!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtzdckr0j0hchn15fknk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtzdckr0j0hchn15fknk.png" alt="A tenfold reduction in fetch time for IntelliJ Platform project in TeamCity" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: if you’re using Windows, the performance improvements might not be so impressive. But still they can be noticeable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try native Git on your server
&lt;/h2&gt;

&lt;p&gt;Before you try native Git on your TeamCity server, we suggest taking a look at the &lt;a href="https://www.jetbrains.com/help/teamcity/known-issues.html?_gl=1*1bvseab*_ga*MTQ0MDU0NzAxNS4xNjI2OTYxMjU2*_ga_9J976DJZ68*MTY1NzYzNjEyMy4xMjUuMS4xNjU3NjM4MDk0LjA.&amp;amp;_ga=2.90329746.985314392.1657526832-1440547015.1626961256#Known+issues+of+native+Git+checkout" rel="noopener noreferrer"&gt;known issues&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;To enable native Git, navigate to Administration | Diagnostics and open the Git tab there. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FiZPMflETZwHvNpuFm9hcibepCrydUZ9thKxVtXkjjUS7cs_shITK19wjGHshbeEu0oo6I-7V-Y9fHcj2xmSnFPXOjCs8bs-y_LII1577U_xeq2An4NXcj7TBjErliAk_m5FbCQTyKqGYVUxJOw" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FiZPMflETZwHvNpuFm9hcibepCrydUZ9thKxVtXkjjUS7cs_shITK19wjGHshbeEu0oo6I-7V-Y9fHcj2xmSnFPXOjCs8bs-y_LII1577U_xeq2An4NXcj7TBjErliAk_m5FbCQTyKqGYVUxJOw" alt="TeamCity diagnostics page" width="1600" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On this page, you can test the connection via native Git for any of the VCS roots on your server. If you choose to test all VCS roots, TeamCity will check whether they successfully connect via JGit and then will test their connection via native Git. This measure helps ensure that none of your pipelines will break after switching to native Git. If the connection test is successful, then you can enable native Git support on your server.&lt;/p&gt;

&lt;p&gt;Give it a try and tell us about your experience! We’re looking forward to your feedback.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>git</category>
      <category>devops</category>
      <category>teamcity</category>
    </item>
  </channel>
</rss>
