<?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: Xianpeng Shen</title>
    <description>The latest articles on Forem by Xianpeng Shen (@shenxianpeng).</description>
    <link>https://forem.com/shenxianpeng</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%2F289026%2Fd0b1d1d2-19d2-4754-a8c6-f6f0c0911a34.jpg</url>
      <title>Forem: Xianpeng Shen</title>
      <link>https://forem.com/shenxianpeng</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/shenxianpeng"/>
    <language>en</language>
    <item>
      <title>cpp-linter-hooks: The Most Complete pre-commit Solution for C/C++ Projects</title>
      <dc:creator>Xianpeng Shen</dc:creator>
      <pubDate>Wed, 20 May 2026 05:11:08 +0000</pubDate>
      <link>https://forem.com/shenxianpeng/cpp-linter-hooks-the-most-complete-pre-commit-solution-for-cc-projects-1ddi</link>
      <guid>https://forem.com/shenxianpeng/cpp-linter-hooks-the-most-complete-pre-commit-solution-for-cc-projects-1ddi</guid>
      <description>&lt;p&gt;If you work on Python projects, you've probably used &lt;code&gt;pre-commit&lt;/code&gt; — running &lt;code&gt;black&lt;/code&gt;, &lt;code&gt;ruff&lt;/code&gt;, &lt;code&gt;mypy&lt;/code&gt; before every &lt;code&gt;git commit&lt;/code&gt;, blocking anything that doesn't meet the standard. This workflow is well-established in the Python ecosystem.&lt;/p&gt;

&lt;p&gt;For C/C++ projects, it's a different story.&lt;/p&gt;

&lt;p&gt;The official &lt;code&gt;mirrors-clang-format&lt;/code&gt; hook only handles formatting. If you want clang-tidy for static analysis, you're on your own. Features like compilation database auto-detection, version pinning, or auto-fix? Not even on the radar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cpp-linter/cpp-linter-hooks" rel="noopener noreferrer"&gt;cpp-linter-hooks&lt;/a&gt; fills this gap. It provides both &lt;code&gt;clang-format&lt;/code&gt; and &lt;code&gt;clang-tidy&lt;/code&gt; hooks in a single pre-commit repo, along with the supporting capabilities that C/C++ projects actually need.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Not Just Use mirrors-clang-format?
&lt;/h2&gt;

&lt;p&gt;Here's a quick comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;cpp-linter-hooks&lt;/th&gt;
&lt;th&gt;mirrors-clang-format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;clang-format&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;clang-tidy&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inline style string (&lt;code&gt;--style&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool version pinning (&lt;code&gt;--version&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ (via rev tag)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom &lt;code&gt;.clang-tidy&lt;/code&gt; config&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compilation database auto-detection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dry-run mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-fix (&lt;code&gt;--fix&lt;/code&gt; for clang-tidy)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verbose output&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel execution (&lt;code&gt;--jobs&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;mirrors-clang-format&lt;/code&gt; does one thing: download a &lt;code&gt;clang-format&lt;/code&gt; binary and run it on changed files. If formatting is all you need, it works fine.&lt;/p&gt;

&lt;p&gt;But in real-world C/C++ projects, the true headache isn't inconsistent formatting — it's clang-tidy diagnostics: memory leaks, undefined behavior, performance pitfalls. These are exactly the issues worth catching at commit time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;p&gt;Add this to your &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/cpp-linter/cpp-linter-hooks&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1.4.1&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clang-format&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--style=file&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clang-tidy&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--checks=.clang-tidy&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pre-commit &lt;span class="nb"&gt;install
&lt;/span&gt;pre-commit run &lt;span class="nt"&gt;--all-files&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first run downloads the clang tools from PyPI. Subsequent runs use the cached environment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Configuration Details
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pin Your Tool Version
&lt;/h3&gt;

&lt;p&gt;An easy detail to miss: &lt;code&gt;rev&lt;/code&gt; is the project version of cpp-linter-hooks, not the clang tool version. Without an explicit version, upgrading &lt;code&gt;rev&lt;/code&gt; may silently change your clang-format or clang-tidy version, leading to inconsistent results across your team.&lt;/p&gt;

&lt;p&gt;Always add &lt;code&gt;--version&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clang-format&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--style=file&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;--version=21&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clang-tidy&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--checks=.clang-tidy&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;--version=21&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This locks the tool at clang 21 regardless of project &lt;code&gt;rev&lt;/code&gt; upgrades.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compilation Database
&lt;/h3&gt;

&lt;p&gt;clang-tidy needs compiler flags for accurate static analysis. If your project uses CMake or Meson, generate &lt;code&gt;compile_commands.json&lt;/code&gt; and cpp-linter-hooks auto-detects it from common build directories (&lt;code&gt;build/&lt;/code&gt;, &lt;code&gt;out/&lt;/code&gt;, &lt;code&gt;cmake-build-debug/&lt;/code&gt;, etc.) — no extra configuration needed.&lt;/p&gt;

&lt;p&gt;You can also specify it explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clang-tidy&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--compile-commands=build&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;--checks=.clang-tidy&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To generate the compilation database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cmake &lt;span class="nt"&gt;-DCMAKE_EXPORT_COMPILE_COMMANDS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="nt"&gt;-Bbuild&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Auto-Fix
&lt;/h3&gt;

&lt;p&gt;clang-tidy's &lt;code&gt;--fix&lt;/code&gt; can auto-apply fixes for certain checks. cpp-linter-hooks supports this since v1.4.0, but it's opt-in — auto-modifying source code carries risk, and you should decide whether you trust it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clang-tidy&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--checks=.clang-tidy&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;--fix&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: enabling &lt;code&gt;--fix&lt;/code&gt; automatically disables parallel execution (&lt;code&gt;--jobs&lt;/code&gt;) to prevent concurrent writes to the same header file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Running full clang-tidy on a large codebase can be slow. Two ways to optimize:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limit scope&lt;/strong&gt; with the &lt;code&gt;files&lt;/code&gt; filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clang-tidy&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--checks=.clang-tidy&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;--version=21&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Enable parallelism&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clang-tidy&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;--checks=.clang-tidy&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;--jobs=4&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For day-to-day development, you can also check only changed files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pre-commit run &lt;span class="nt"&gt;--files&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Relationship with cpp-linter-action
&lt;/h2&gt;

&lt;p&gt;If you've looked into C/C++ CI tooling, you might have seen &lt;a href="https://github.com/cpp-linter/cpp-linter-action" rel="noopener noreferrer"&gt;cpp-linter-action&lt;/a&gt; (139 stars on GitHub Marketplace). It's a GitHub Action that runs clang-format and clang-tidy in CI pipelines and surfaces results as file annotations, thread comments, and PR reviews.&lt;/p&gt;

&lt;p&gt;cpp-linter-hooks and cpp-linter-action are two complementary tools under the same organization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;cpp-linter-action&lt;/strong&gt;: runs in CI, designed for the PR review workflow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cpp-linter-hooks&lt;/strong&gt;: runs locally before &lt;code&gt;git commit&lt;/code&gt;, designed for daily development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both share the same &lt;code&gt;.clang-format&lt;/code&gt; and &lt;code&gt;.clang-tidy&lt;/code&gt; configuration files. Code that passes locally won't break in CI — a classic "local + CI dual-gate" pattern.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;cpp-linter-hooks is one of the main projects I maintain under the cpp-linter organization. Since 2022, it has grown to include version pinning, compilation database detection, auto-fix, and parallel execution — covering the core needs of C/C++ projects at the pre-commit stage.&lt;/p&gt;

&lt;p&gt;If you develop in C/C++ or maintain a C/C++ open-source project, give it a try. Add it to your &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;, and within minutes you'll have automatic formatting and static analysis running before every commit — no more waiting for CI to go red before fixing things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/cpp-linter/cpp-linter-hooks" rel="noopener noreferrer"&gt;https://github.com/cpp-linter/cpp-linter-hooks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/cpp-linter-hooks/" rel="noopener noreferrer"&gt;https://pypi.org/project/cpp-linter-hooks/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Issues and feedback are welcome on GitHub.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>c</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Building an AI Agent Inside Jira —— A Jira Copilot Implementation Guide</title>
      <dc:creator>Xianpeng Shen</dc:creator>
      <pubDate>Wed, 13 May 2026 17:44:23 +0000</pubDate>
      <link>https://forem.com/shenxianpeng/building-an-ai-agent-inside-jira-a-jira-copilot-implementation-guide-2baj</link>
      <guid>https://forem.com/shenxianpeng/building-an-ai-agent-inside-jira-a-jira-copilot-implementation-guide-2baj</guid>
      <description>&lt;p&gt;Lately I've been getting the same question over and over: how do you build an AI Agent inside Jira, something like GitHub Copilot but for Jira?&lt;/p&gt;

&lt;p&gt;I wasn't planning to write about this — the concept didn't seem particularly complex, and I figured anyone with the relevant background could piece it together from the docs. But after being asked enough times, I realized a lot of people genuinely aren't familiar with this area.&lt;/p&gt;

&lt;p&gt;I happened to build a similar application inside Jira recently, so here's the full implementation approach.&lt;/p&gt;

&lt;p&gt;The guiding principle is simple: &lt;strong&gt;use existing services wherever possible. Don't build from scratch.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let me walk through it step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a Bot Account
&lt;/h3&gt;

&lt;p&gt;First, you need a dedicated bot. If your company's IT policy allows it, create an account with a short, easy-to-remember name — something like &lt;code&gt;copilot&lt;/code&gt; or &lt;code&gt;ai-bot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What does this account do? It acts as a "trigger." When a user @-mentions this account in a Jira comment, the automation pipeline kicks in. That's why the name should be short and easy to type — you don't want your colleagues typing &lt;code&gt;@very-long-hard-to-spell-username-2026&lt;/code&gt; every time they need something.&lt;/p&gt;

&lt;p&gt;This step isn't technically exciting, but it's where the whole flow begins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Set Up Jira Automation
&lt;/h3&gt;

&lt;p&gt;Once the bot account is ready, the next step is configuring Jira Automation. Jira ships with built-in Automation features — no plugins required.&lt;/p&gt;

&lt;p&gt;The logic is straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitor the issue comment section&lt;/li&gt;
&lt;li&gt;When someone @-mentions your target user (e.g., &lt;code&gt;copilot&lt;/code&gt;), immediately fire a webhook&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jira Automation rules are configured visually, no code involved. You set the trigger condition (Comment contains &lt;code&gt;@copilot&lt;/code&gt;), then add a "Send webhook" action pointing to your backend service.&lt;/p&gt;

&lt;p&gt;The key here: &lt;strong&gt;Automation only handles detection and forwarding. It does zero business logic.&lt;/strong&gt; Think of it as a doorbell — someone presses it, the signal goes out, that's it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Use a Webhook to Trigger the Backend Application
&lt;/h3&gt;

&lt;p&gt;Once the webhook fires, something needs to receive it. I used Jenkins with the Jenkins Generic Webhook Trigger Plugin.&lt;/p&gt;

&lt;p&gt;Why Jenkins? Because most teams already have Jenkins running CI/CD. It's existing infrastructure — no need to deploy a new service from scratch.&lt;/p&gt;

&lt;p&gt;The setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a Pipeline Job in Jenkins, configure the Generic Webhook to receive requests from Jira Automation&lt;/li&gt;
&lt;li&gt;When the webhook is triggered, the Pipeline launches your backend Application&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;One thing to get right: the webhook endpoint needs proper security — tokens, source restrictions, parameter validation. You don't want anyone on the internet triggering your Jenkins jobs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This Application is the core piece you'll build. My own implementation is based on the GitHub Copilot SDK, but the principle is universal — you can use whatever AI platform or SDK you're comfortable with, as long as it can call an LLM via API or CLI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Build a Skills Architecture
&lt;/h3&gt;

&lt;p&gt;This is the most important design decision in the whole system: &lt;strong&gt;your Application should not be a monolithic "do-everything" script. Instead, organize AI capabilities through Skills.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My approach is to maintain a dedicated Git repository, structured roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ai-agent/
├── app/          # Core application logic
└── skills/       # Skill definitions
    ├── fix-bug/
    │   └── SKILL.md
    ├── draft-release-note/
    │   └── SKILL.md
    ├── analyze-root-cause/
    │   └── SKILL.md
    └── write-tests/
        └── SKILL.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app/&lt;/code&gt; directory: manages the overall application logic — receiving webhook requests, parsing user intent, dispatching Skills, returning results.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skills/&lt;/code&gt; directory: each Skill is a subdirectory named after the skill, containing a &lt;code&gt;SKILL.md&lt;/code&gt; file (capitalized). This file describes, in natural language, what the skill does, what it takes as input, and what it produces as output. For example, &lt;code&gt;draft-release-note/SKILL.md&lt;/code&gt; might contain: "Based on recent commit records and Jira issue lists, generate a draft release note in Markdown format."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benefits of this design are clear:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Decoupled capabilities&lt;/strong&gt;: adding a new skill just means creating a new subdirectory and &lt;code&gt;SKILL.md&lt;/code&gt; file under &lt;code&gt;skills/&lt;/code&gt; — no changes to core Application code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version-controlled&lt;/strong&gt;: Skills files live in a Git repository with full change history and review mechanisms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy collaboration&lt;/strong&gt;: anyone on the team can submit a new Skill or improve an existing one, without waiting for a developer's schedule.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each time the Application starts up, it scans the &lt;code&gt;skills/&lt;/code&gt; directory to see what capabilities are available, then decides which Skill to invoke based on user input.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: The Actual User Experience
&lt;/h3&gt;

&lt;p&gt;Once this system is running, the user experience looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In any Jira issue's comment section, @-mention your configured user and describe what you need. For example: &lt;code&gt;@copilot generate the release notes for this version&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Jira Automation detects the @-mention event and sends a webhook request&lt;/li&gt;
&lt;li&gt;Jenkins receives the request and starts the Application&lt;/li&gt;
&lt;li&gt;The Application parses user intent and matches it to the appropriate Skill (e.g., &lt;code&gt;draft-release-note&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The AI executes the task according to the Skill definition, then writes the result back as a Jira comment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From the user's perspective, it's just @-mentioning someone and waiting for a reply in Jira — a completely natural interaction pattern.&lt;/p&gt;

&lt;p&gt;In my setup, the tasks that work well include: drafting release notes, analyzing build failure causes, generating root cause analysis drafts, suggesting test code based on context, or (with appropriate repository access) making small code changes.&lt;/p&gt;

&lt;p&gt;From there, you continuously refine the system — mostly the Skills — to make the outputs more stable and reliable over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Lessons Learned and Optimization
&lt;/h3&gt;

&lt;p&gt;Getting the system running is step one. The real work is the continuous optimization that follows. Here are a few lessons I've picked up from hands-on experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Run in containers, not VMs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your Application should run in containers (Docker / Kubernetes), not traditional VMs. Containers start fast, isolate resources well, scale horizontally, and — importantly — each trigger gets a clean execution environment. VMs can work, but image management, dependency conflicts, and operational overhead are an order of magnitude worse. For an AI Agent that gets triggered frequently and needs quick responses, containers are the clear winner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. If a script can do it, don't use AI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the most common mistake — throwing every task at the LLM. The reality is, many operations don't need AI at all. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pulling issue lists from the Jira API, filtering fields, formatting output → plain script.&lt;/li&gt;
&lt;li&gt;Parsing webhook requests, extracting key fields, assembling prompts → preprocessing script.&lt;/li&gt;
&lt;li&gt;Writing AI results back as Jira comments → still a script.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let AI handle only what it's best at: understanding and generating text. All other deterministic logic should be handled by scripts. This not only saves money (fewer tokens consumed) but also produces more stable, predictable results. A useful litmus test: &lt;strong&gt;if you can express the logic clearly in under 50 lines of script, don't make an LLM guess at it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Design Skills for reuse&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Skills aren't disposable. Design them with reuse in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Right-size granularity.&lt;/strong&gt; A Skill does one thing, but that thing should be general enough — for example, &lt;code&gt;analyze-build-failure&lt;/code&gt; should work across multiple projects, not be hardcoded to one repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameterize.&lt;/strong&gt; Use input parameters (project name, version number, date range) to adapt to different scenarios, rather than creating a separate Skill for each one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composable.&lt;/strong&gt; Complex tasks can be built by chaining multiple base Skills. A "weekly release report" might be composed of &lt;code&gt;collect-commits&lt;/code&gt; + &lt;code&gt;draft-release-note&lt;/code&gt;, instead of writing yet another Skill.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Follow Skill authoring best practices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The quality of &lt;code&gt;SKILL.md&lt;/code&gt; directly determines the quality of AI output. Here are the key points I've learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explicit input/output definitions.&lt;/strong&gt; Every Skill must clearly state what it receives (fields, format) and what it produces (text, structure). Don't write "analyze the problem"; write "Receive a Jira Issue Key, read its Description and the last 10 Comments, output a root cause analysis in Chinese, under 200 words."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provide examples.&lt;/strong&gt; Include an input/output example in &lt;code&gt;SKILL.md&lt;/code&gt;. The AI understands your expectations much more accurately with a concrete sample.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define boundaries.&lt;/strong&gt; Explicitly tell the AI what NOT to do. For example: "Do not modify original code, only output suggestions", "Do not fabricate information not present in the issue." A Skill without boundaries gives the AI too much room to improvise, and the results are often unreliable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test iteratively.&lt;/strong&gt; Run the same set of test cases against a Skill repeatedly, comparing output quality after each edit to &lt;code&gt;SKILL.md&lt;/code&gt;. This is essentially unit testing — except the subject under test is the AI's prompt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Log token consumption for optimization comparison&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is easy to overlook but critically important: in your Application logs, &lt;strong&gt;explicitly record the token count for every request&lt;/strong&gt; (input tokens, output tokens, total tokens).&lt;/p&gt;

&lt;p&gt;Why? Because optimization needs a quantifiable metric. You tweak a prompt, restructure a Skill, switch models — how many tokens did those changes save? Without logging, you're judging by feel. With data, a glance at the logs tells you clearly: same task, token consumption dropped from 2000 to 1200 — optimization confirmed.&lt;/p&gt;

&lt;p&gt;I recommend logging these fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;timestamp&lt;/code&gt;: request time&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skill_name&lt;/code&gt;: the matched Skill&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;model&lt;/code&gt;: the model used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;input_tokens&lt;/code&gt; / &lt;code&gt;output_tokens&lt;/code&gt; / &lt;code&gt;total_tokens&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;latency_ms&lt;/code&gt;: total time (network + inference)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_input&lt;/code&gt;: a summary of the original user input (for traceability)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once this becomes a habit, every change can be validated quickly, and you'll never have to guess which direction to optimize.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap-Up
&lt;/h3&gt;

&lt;p&gt;That's the high-level implementation approach, along with the pitfalls I've hit and the lessons learned along the way. I won't go into specific code or technical details — every company has different tech stacks, permission models, and internal processes, so directly copy-pasting wouldn't work anyway.&lt;/p&gt;

&lt;p&gt;But once you understand the workflow behind these six steps, you can absolutely build a similar system with AI assistance, tailored to your own company's reality.&lt;/p&gt;

&lt;p&gt;At its core, this isn't anything particularly mysterious. It's essentially creating an AI-capable robot — a "digital colleague" — that operates inside Jira.&lt;/p&gt;

&lt;p&gt;Before, you'd @-mention a teammate in Jira and ask them to write release notes, run tests, or fix a bug. Now, you can @-mention this new digital colleague and have it handle those tasks.&lt;/p&gt;

&lt;p&gt;And that, I think, is where AI creates real value inside organizations: making the work that used to require endless back-and-forth communication more automatic, more seamless.&lt;/p&gt;

&lt;p&gt;Hope this gives you some ideas. If you're building something similar, I'd love to hear about it in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>beginners</category>
      <category>devops</category>
    </item>
    <item>
      <title>Thank you for sharing the Conventional Branch.</title>
      <dc:creator>Xianpeng Shen</dc:creator>
      <pubDate>Tue, 16 Sep 2025 13:05:31 +0000</pubDate>
      <link>https://forem.com/shenxianpeng/thank-you-for-sharing-the-conventional-branch-2pfm</link>
      <guid>https://forem.com/shenxianpeng/thank-you-for-sharing-the-conventional-branch-2pfm</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/louis7/from-conventional-commits-to-conventional-branch-4flp" class="crayons-story__hidden-navigation-link"&gt;From Conventional Commits to Conventional Branch&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/louis7" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F929271%2Fd8eb2758-2c0a-4cc2-aec3-c3ed531cae08.png" alt="louis7 profile" class="crayons-avatar__image" width="250" height="250"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/louis7" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Louis Liu
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Louis Liu
                
              
              &lt;div id="story-author-preview-content-2342796" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/louis7" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F929271%2Fd8eb2758-2c0a-4cc2-aec3-c3ed531cae08.png" class="crayons-avatar__image" alt="" width="250" height="250"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Louis Liu&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/louis7/from-conventional-commits-to-conventional-branch-4flp" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 26 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/louis7/from-conventional-commits-to-conventional-branch-4flp" id="article-link-2342796"&gt;
          From Conventional Commits to Conventional Branch
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/git"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;git&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/github"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;github&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/louis7/from-conventional-commits-to-conventional-branch-4flp" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;3&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/louis7/from-conventional-commits-to-conventional-branch-4flp#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>programming</category>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>New Jenkins Plugin: Let AI Explain Your Build Failures</title>
      <dc:creator>Xianpeng Shen</dc:creator>
      <pubDate>Fri, 01 Aug 2025 18:00:49 +0000</pubDate>
      <link>https://forem.com/shenxianpeng/new-jenkins-plugin-let-ai-explain-your-build-failures-26lo</link>
      <guid>https://forem.com/shenxianpeng/new-jenkins-plugin-let-ai-explain-your-build-failures-26lo</guid>
      <description>&lt;p&gt;Recently, I released my &lt;strong&gt;first-ever Jenkins plugin&lt;/strong&gt; – and &lt;a href="https://plugins.jenkins.io/explain-error/" rel="noopener noreferrer"&gt;it's now officially available in the Jenkins Center!&lt;/a&gt; 🎉&lt;/p&gt;

&lt;p&gt;This plugin makes it possible to &lt;strong&gt;analyze build errors with AI directly inside Jenkins&lt;/strong&gt;, so you no longer need to copy and paste logs into ChatGPT or other tools. Instead, you'll see an &lt;strong&gt;"Explain Error" button right in the console output&lt;/strong&gt;, and you can also use the &lt;code&gt;explainError()&lt;/code&gt; step in your pipeline to trigger AI analysis automatically when a build fails.&lt;/p&gt;

&lt;p&gt;This is my first contribution to the Jenkins plugin ecosystem. I used to think most things could be handled by pipeline scripts, and there wasn’t much need for custom plugins. But as AI becomes increasingly mainstream, I noticed something surprising: &lt;strong&gt;Jenkins still didn’t have a plugin for AI-based error explanation&lt;/strong&gt;. So, I decided to build one myself.&lt;/p&gt;

&lt;p&gt;With the help of AI and some late-night coding sessions, along with several rounds of thorough code review from the Jenkins Hosting team, the plugin finally went live last weekend. 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the Plugin
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Explain Error Plugin&lt;/strong&gt; is an OpenAI-powered Jenkins plugin that can automatically analyze logs from failed builds and generate easy-to-understand explanations. It works with both Pipeline and Freestyle job types.&lt;/p&gt;

&lt;p&gt;GitHub repo: &lt;a href="https://github.com/jenkinsci/explain-error-plugin" rel="noopener noreferrer"&gt;https://github.com/jenkinsci/explain-error-plugin&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;👉 &lt;a href="https://youtu.be/rPI9PMeDQ2o?si=YMeprtSz9VmqglCL" rel="noopener noreferrer"&gt;Watch the hands-on demo on YouTube&lt;/a&gt; — setup, run, and see how AI explains your Jenkins job failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✅ One-click console error explanation&lt;/td&gt;
&lt;td&gt;Adds an “Explain Error” button to the build log view&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Pipeline support&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;explainError()&lt;/code&gt; in your pipeline scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Custom model support&lt;/td&gt;
&lt;td&gt;Choose GPT-3.5 or other models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Jenkins CasC compatible&lt;/td&gt;
&lt;td&gt;Supports Configuration as Code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ Log filtering&lt;/td&gt;
&lt;td&gt;Use regex patterns to focus on error content&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Jenkins version ≥ &lt;strong&gt;2.479.3&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Java version ≥ &lt;strong&gt;17&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;OpenAI API key&lt;/strong&gt; (you can get one at &lt;a href="https://platform.openai.com/account/api-keys" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Install
&lt;/h2&gt;

&lt;p&gt;Go to &lt;strong&gt;Manage Jenkins → Manage Plugins → Available&lt;/strong&gt;, then search for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Explain Error Plugin”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And install it like any other Jenkins plugin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;Once installed, head to &lt;code&gt;Manage Jenkins → Configure System&lt;/code&gt; and scroll to &lt;strong&gt;Explain Error Plugin Configuration&lt;/strong&gt; to enter your OpenAI settings.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Enable Explanation&lt;/td&gt;
&lt;td&gt;Enable/disable AI explanation&lt;/td&gt;
&lt;td&gt;✅ Enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Key&lt;/td&gt;
&lt;td&gt;Your OpenAI API key&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API URL&lt;/td&gt;
&lt;td&gt;OpenAI endpoint&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.openai.com/v1/chat/completions&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Model&lt;/td&gt;
&lt;td&gt;Model to use&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpt-3.5-turbo&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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%2F0lrtdzedrafx88x5hox8.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%2F0lrtdzedrafx88x5hox8.png" alt="Explain Error Plugin Configuration" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prefer managing Jenkins with Configuration as Code? You can configure it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;unclassified&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;explainError&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enableExplanation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${AI_API_KEY}"&lt;/span&gt;
    &lt;span class="na"&gt;apiUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.openai.com/v1/chat/completions"&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-3.5-turbo"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Use It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  In Your Pipeline
&lt;/h3&gt;

&lt;p&gt;Best used in a &lt;code&gt;post { failure { ... } }&lt;/code&gt; block so it automatically analyzes failures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;explainError&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also customize how logs are filtered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;explainError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;maxLines:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;logPattern:&lt;/span&gt; &lt;span class="s1"&gt;'(?i)(error|failed|exception)'&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  In Console Output
&lt;/h3&gt;

&lt;p&gt;This works for any job type:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the console output of a failed build&lt;/li&gt;
&lt;li&gt;Click the “Explain Error” button at the top&lt;/li&gt;
&lt;li&gt;The AI-generated explanation will appear below the button&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Demo Preview
&lt;/h2&gt;

&lt;p&gt;When a build fails, you’ll see a sidebar entry on the build page where the AI explanation will be shown:&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%2F9j9u1furycebwmccbx46.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%2F9j9u1furycebwmccbx46.png" alt="Explain Error Plugin" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you can view the explanation directly on the console page after clicking the “Explain Error” 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixwgmsz5uwstndipwete.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%2Fixwgmsz5uwstndipwete.png" alt="Explain Error Plugin Console" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error caching&lt;/strong&gt;: Avoid redundant API calls for the same errors (already implemented, pending merge)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-model support&lt;/strong&gt;: Plan to support other AI services like Gemini, Claude, DeepSeek, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More features are under development or in the idea phase — and your feedback is always welcome!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The plugin is 100% open source — contributions and suggestions are very welcome!&lt;/p&gt;

&lt;p&gt;If you try the plugin and find it useful, feel free to share this article, or give the project a ⭐ on GitHub:&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/jenkinsci/explain-error-plugin" rel="noopener noreferrer"&gt;https://github.com/jenkinsci/explain-error-plugin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s the best way to support open-source work like this. 🙌&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>jenkins</category>
      <category>ai</category>
      <category>devops</category>
      <category>ci</category>
    </item>
    <item>
      <title>C/C++ Lint Action | clang-format &amp; clang-tidy</title>
      <dc:creator>Xianpeng Shen</dc:creator>
      <pubDate>Fri, 26 Nov 2021 13:49:33 +0000</pubDate>
      <link>https://forem.com/shenxianpeng/cc-lint-action-clang-format-clang-tidy-2o18</link>
      <guid>https://forem.com/shenxianpeng/cc-lint-action-clang-format-clang-tidy-2o18</guid>
      <description>&lt;h3&gt;
  
  
  My Workflow
&lt;/h3&gt;

&lt;p&gt;A Github Action for linting C/C++ code integrating clang-tidy and clang-format to collect feedback provided in the form of thread comments and/or annotations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Maintainer Must-Haves&lt;/p&gt;

&lt;h3&gt;
  
  
  Yaml File or Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/cpp-linter" rel="noopener noreferrer"&gt;
        cpp-linter
      &lt;/a&gt; / &lt;a href="https://github.com/cpp-linter/cpp-linter-action" rel="noopener noreferrer"&gt;
        cpp-linter-action
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Github Action for linting C/C++ code integrating clang-tidy and clang-format to collect feedback provided in the form of file-annotations, thread-comments, workflow step-summary, and Pull Request reviews.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;C/C++ Linter Action &lt;sup&gt;| clang-format &amp;amp; clang-tidy&lt;/sup&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/8e796160bb3d3443e229e628283290e74dbd96127d0c2a5ad9698f4dc5fa001e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6370702d6c696e7465722f6370702d6c696e7465722d616374696f6e"&gt;&lt;img src="https://camo.githubusercontent.com/8e796160bb3d3443e229e628283290e74dbd96127d0c2a5ad9698f4dc5fa001e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6370702d6c696e7465722f6370702d6c696e7465722d616374696f6e" alt="GitHub release (latest SemVer)"&gt;&lt;/a&gt;
&lt;a href="https://github.com/marketplace/actions/c-c-linter" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e94cbd13fbdf76cfa6155e66519c2a285c3c7ecad2c523826d9a85e4fcffa334/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d61726b6574706c6163652d43253246432532422532422532304c696e7465722d626c75653f6c6f676f3d676974687562" alt="GitHub marketplace"&gt;&lt;/a&gt;
&lt;a href="https://github.com/cpp-linter/cpp-linter-action/actions/workflows/cpp-linter.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/cpp-linter/cpp-linter-action/actions/workflows/cpp-linter.yml/badge.svg" alt="cpp-linter"&gt;&lt;/a&gt;
&lt;a href="https://github.com/cpp-linter/cpp-linter-action/actions/workflows/mkdocs-deploy.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/cpp-linter/cpp-linter-action/actions/workflows/mkdocs-deploy.yml/badge.svg" alt="MkDocs Deploy"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9a356c958736ca21870028e2da359c2a58807b516e7fb39e2aa57d4089aa8d93/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6370702d6c696e7465722f6370702d6c696e7465722d616374696f6e3f6c6162656c3d6c6963656e7365266c6f676f3d676974687562"&gt;&lt;img src="https://camo.githubusercontent.com/9a356c958736ca21870028e2da359c2a58807b516e7fb39e2aa57d4089aa8d93/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6370702d6c696e7465722f6370702d6c696e7465722d616374696f6e3f6c6162656c3d6c6963656e7365266c6f676f3d676974687562" alt="GitHub"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A Github Action for linting C/C++ code integrating clang-tidy and clang-format
to collect feedback provided in the form of
&lt;a href="https://cpp-linter.github.io/cpp-linter-action/inputs-outputs/#file-annotations" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;file-annotations&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://cpp-linter.github.io/cpp-linter-action/inputs-outputs/#thread-comments" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;thread-comments&lt;/code&gt;&lt;/a&gt;
workflow &lt;a href="https://cpp-linter.github.io/cpp-linter-action/inputs-outputs/#step-summary" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;step-summary&lt;/code&gt;&lt;/a&gt;, and Pull Request reviews (with
&lt;a href="https://cpp-linter.github.io/cpp-linter-action/inputs-outputs/#tidy-review" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;tidy-review&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://cpp-linter.github.io/cpp-linter-action/inputs-outputs/#format-review" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;format-review&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Create a new GitHub Actions workflow in your project, e.g. at &lt;a href="https://github.com/cpp-linter/cpp-linter-action/blob/main/.github/workflows/cpp-linter.yml" rel="noopener noreferrer"&gt;.github/workflows/cpp-linter.yml&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The content of the file should be in the following format.&lt;/p&gt;
&lt;div class="highlight highlight-source-yaml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;    &lt;span class="pl-ent"&gt;steps&lt;/span&gt;:
      - &lt;span class="pl-ent"&gt;uses&lt;/span&gt;: &lt;span class="pl-s"&gt;actions/checkout@v5&lt;/span&gt;
      - &lt;span class="pl-ent"&gt;uses&lt;/span&gt;: &lt;span class="pl-s"&gt;cpp-linter/cpp-linter-action@v2&lt;/span&gt;
        &lt;span class="pl-ent"&gt;id&lt;/span&gt;: &lt;span class="pl-s"&gt;linter&lt;/span&gt;
        &lt;span class="pl-ent"&gt;env&lt;/span&gt;:
          &lt;span class="pl-ent"&gt;GITHUB_TOKEN&lt;/span&gt;: &lt;span class="pl-s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
        &lt;span class="pl-ent"&gt;with&lt;/span&gt;:
          &lt;span class="pl-ent"&gt;style&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;file&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;  &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Use .clang-format config file&lt;/span&gt;
          &lt;span class="pl-ent"&gt;tidy-checks&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Use .clang-tidy config file&lt;/span&gt;
          &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; only 'update' a single comment in a pull request thread.&lt;/span&gt;
          &lt;span class="pl-ent"&gt;thread-comments&lt;/span&gt;: &lt;span class="pl-s"&gt;${{ github.event_name == 'pull_request' &amp;amp;&amp;amp; 'update' }}&lt;/span&gt;
      - &lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;Fail fast?!&lt;/span&gt;
        &lt;span class="pl-ent"&gt;if&lt;/span&gt;: &lt;span class="pl-s"&gt;steps.linter.outputs.checks-failed &amp;gt; 0&lt;/span&gt;
        &lt;span class="pl-ent"&gt;run&lt;/span&gt;: &lt;span class="pl-s"&gt;exit 1&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;For all explanations of our available input parameters and…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/cpp-linter/cpp-linter-action" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://github.com/cpp-linter/cpp-linter-action/blob/master/.github/workflows/cpp-linter.yml" rel="noopener noreferrer"&gt;cpp-linter.yml&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cpp-linter&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reopened&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# let PR-synchronize events be handled by push events&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cpp-linter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cpp-linter/cpp-linter-action@v2&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linter&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;file&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fail fast?!&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;steps.linter.outputs.checks-failed &amp;gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "Some files failed the linting checks!"&lt;/span&gt;
        &lt;span class="c1"&gt;# for actual deployment&lt;/span&gt;
        &lt;span class="c1"&gt;# run: exit 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://cpp-linter.github.io/cpp-linter-action/" rel="noopener noreferrer"&gt;https://cpp-linter.github.io/cpp-linter-action/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Annotations&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%2Fgithub.com%2Fshenxianpeng%2Fcpp-linter-action%2Fraw%2Fmaster%2Fdocs%2Fimages%2Fannotations-clang-format.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%2Fgithub.com%2Fshenxianpeng%2Fcpp-linter-action%2Fraw%2Fmaster%2Fdocs%2Fimages%2Fannotations-clang-format.png" alt="annotations-clang-format" width="800" height="400"&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%2Fgithub.com%2Fshenxianpeng%2Fcpp-linter-action%2Fraw%2Fmaster%2Fdocs%2Fimages%2Fannotations-clang-tidy.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%2Fgithub.com%2Fshenxianpeng%2Fcpp-linter-action%2Fraw%2Fmaster%2Fdocs%2Fimages%2Fannotations-clang-tidy.png" alt="annotations-clang-tidy" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thread Comment&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%2Fkt9j9ymi7mkkcfx0nuag.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%2Fkt9j9ymi7mkkcfx0nuag.png" alt="Thread Comment" width="800" height="939"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>actionshackathon21</category>
      <category>opensource</category>
      <category>githubactions</category>
      <category>clangformat</category>
    </item>
  </channel>
</rss>
