<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jefster Farlei Fernandes Caixeta Junior</title>
    <description>The latest articles on DEV Community by Jefster Farlei Fernandes Caixeta Junior (@jefster_farleifernandes).</description>
    <link>https://dev.to/jefster_farleifernandes</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%2F2877311%2F84e7d3a9-424d-491c-a539-6e627c137dfc.jpg</url>
      <title>DEV Community: Jefster Farlei Fernandes Caixeta Junior</title>
      <link>https://dev.to/jefster_farleifernandes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jefster_farleifernandes"/>
    <language>en</language>
    <item>
      <title>Automating Remote Branch Cleanup in Azure DevOps Using Git and Bash</title>
      <dc:creator>Jefster Farlei Fernandes Caixeta Junior</dc:creator>
      <pubDate>Fri, 07 Mar 2025 14:08:15 +0000</pubDate>
      <link>https://dev.to/jefster_farleifernandes/automating-remote-branch-cleanup-in-azure-devops-using-git-and-bash-231g</link>
      <guid>https://dev.to/jefster_farleifernandes/automating-remote-branch-cleanup-in-azure-devops-using-git-and-bash-231g</guid>
      <description>&lt;p&gt;Managing remote branches is crucial in keeping a Git repository clean and efficient. Over time, stale branches accumulate, making navigation harder and slowing down repository operations. In Azure DevOps, branches that haven't been used in months can clutter your repository, potentially causing confusion and unnecessary storage costs.&lt;/p&gt;

&lt;p&gt;This article presents a Bash script to automate the deletion of remote branches that haven't been modified in over three months. By the end of this guide, you'll have a simple but powerful tool to maintain a clean repository in Azure Repos.&lt;/p&gt;

&lt;p&gt;Why Delete Old Remote Branches?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce Clutter – Old feature branches make the repository hard to navigate.&lt;/li&gt;
&lt;li&gt;Improve Performance – Fewer branches mean faster Git operations.&lt;/li&gt;
&lt;li&gt;Enforce Best Practices – Encourages developers to clean up after merging.&lt;/li&gt;
&lt;li&gt;Save Storage Space – Reducing unnecessary data stored in Azure DevOps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Problem: Stale Branches in Azure DevOps&lt;/p&gt;

&lt;p&gt;If you're working on an Azure DevOps repository, you may notice an increasing number of old branches that are no longer relevant. Manually identifying and deleting these branches is tedious, especially in large teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Automate Cleanup with Bash + Git
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;1. We can automate this process by writing a Bash script that:&lt;/li&gt;
&lt;li&gt;2. Fetches all remote branches.&lt;/li&gt;
&lt;li&gt;3. Check the last commit date for each branch.&lt;/li&gt;
&lt;li&gt;4. Deletes branches that haven't been modified in 3+ months.&lt;/li&gt;
&lt;li&gt;Asks for confirmation before deleting.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Bash Script
&lt;/h2&gt;

&lt;p&gt;Below is a fully automated script to clean up remote branches in Azure DevOps repositories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

# Remote repository (default to origin)
REMOTE=${1:-origin}

# Time threshold (3 months ago)
THRESHOLD_DATE=$(date -d "3 months ago" +%s)

# Fetch latest remote branches
git fetch --prune $REMOTE

echo "Checking remote branches older than 3 months..."

# Get remote branches and last commit date
OLD_BRANCHES=()
while read -r branch last_commit_date; do
    # Convert last commit date to Unix timestamp
    LAST_COMMIT_TIMESTAMP=$(date -d "$last_commit_date" +%s)

    # Compare with threshold
    if [[ "$LAST_COMMIT_TIMESTAMP" -lt "$THRESHOLD_DATE" ]]; then
        OLD_BRANCHES+=("$branch")
    fi
done &amp;lt; &amp;lt;(git for-each-ref --format '%(refname:short) %(committerdate:iso8601)' refs/remotes/$REMOTE | sed "s#refs/remotes/$REMOTE/##")

# If no old branches, exit
if [[ ${#OLD_BRANCHES[@]} -eq 0 ]]; then
    echo "No branches older than 3 months found."
    exit 0
fi

# Show branches to be deleted
echo "The following branches are older than 3 months and will be deleted:"
printf '%s\n' "${OLD_BRANCHES[@]}"

# Confirm deletion
read -p "Are you sure you want to delete these branches from Azure DevOps? (y/N): " CONFIRM
if [[ "$CONFIRM" != "y" ]]; then
    echo "Operation aborted."
    exit 0
fi

# Delete branches from Azure DevOps
for branch in "${OLD_BRANCHES[@]}"; do
    echo "Deleting $REMOTE/$branch from Azure DevOps..."
    git push $REMOTE --delete "$branch"
done

echo "Old branches successfully deleted from Azure DevOps."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  Automatically Detects Old Branches
&lt;/h3&gt;

&lt;p&gt;The script checks when each branch was last modified.&lt;/p&gt;

&lt;p&gt;Uses git for-each-ref to get the last commit timestamp.&lt;/p&gt;

&lt;p&gt;Compares timestamps to filter branches older than 3 months.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevents Accidental Deletion
&lt;/h3&gt;

&lt;p&gt;List branches before deleting them.&lt;/p&gt;

&lt;p&gt;Ask for confirmation before proceeding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure DevOps Compatible
&lt;/h3&gt;

&lt;p&gt;Works with Azure Repos (Git) in Azure DevOps.&lt;/p&gt;

&lt;p&gt;Uses git push origin --delete  to remove branches remotely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customizable
&lt;/h3&gt;

&lt;p&gt;Change the time threshold by modifying 3 months ago.&lt;/p&gt;

&lt;p&gt;Change REMOTE=${1:-origin} to work with different Git remotes.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠 How to Use the Script
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Save the Script
&lt;/h3&gt;

&lt;p&gt;Create a new file called delete_old_devops_branches.sh and paste the script inside.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make it Executable
&lt;/h3&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;code&gt;chmod +x delete_old_devops_branches.sh&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Run the Script
&lt;/h3&gt;

&lt;p&gt;Execute the script in your repository:&lt;br&gt;
&lt;code&gt;./delete_old_devops_branches.sh&lt;/code&gt;&lt;br&gt;
Or specify a different remote (if not origin):&lt;br&gt;
&lt;code&gt;./delete_old_devops_branches.sh upstream&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Enhancing the Script (Optional)
&lt;/h2&gt;

&lt;p&gt;Want to add more features? Here are some ideas:&lt;/p&gt;
&lt;h3&gt;
  
  
  Exclude Protected Branches (Main, Develop, etc.)
&lt;/h3&gt;

&lt;p&gt;Modify the script to skip the deletion of main, develop, or other critical branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXCLUDED_BRANCHES=("main" "develop" "release")
if [[ " ${EXCLUDED_BRANCHES[@]} " =~ " $branch " ]]; then
    continue
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run in Dry-Run Mode
&lt;/h3&gt;

&lt;p&gt;Instead of deleting, list the branches:&lt;br&gt;
&lt;code&gt;git push --dry-run $REMOTE --delete "$branch"&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Schedule Automatic Cleanup
&lt;/h3&gt;

&lt;p&gt;Use cron jobs to run the script monthly:&lt;br&gt;
&lt;code&gt;crontab -e&lt;/code&gt;&lt;br&gt;
Add this line:&lt;br&gt;
&lt;code&gt;0 2 1 * * /path/to/delete_old_devops_branches.sh&lt;/code&gt;&lt;br&gt;
This will run the script on the 1st of every month at 2 AM.&lt;/p&gt;

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

&lt;p&gt;Cleaning up remote branches in Azure DevOps is essential for maintaining a healthy Git repository. By automating this task with a simple Bash script, you save time, improve repository organization, and enforce best practices across your team.&lt;/p&gt;

&lt;p&gt;This script is a starting point—you can extend it further with exclusions, dry-run mode, or automatic scheduling.&lt;/p&gt;

&lt;p&gt;💡 Have any ideas to improve it? Share your thoughts in the comments!&lt;/p&gt;

</description>
      <category>azure</category>
      <category>git</category>
      <category>bash</category>
      <category>azurerepos</category>
    </item>
    <item>
      <title>Wrappers in Java and Spring Boot: What They Are, When to Use, and When to Create Custom Ones</title>
      <dc:creator>Jefster Farlei Fernandes Caixeta Junior</dc:creator>
      <pubDate>Mon, 17 Feb 2025 21:15:15 +0000</pubDate>
      <link>https://dev.to/jefster_farleifernandes/wrappers-in-java-and-spring-boot-what-they-are-when-to-use-and-when-to-create-custom-ones-193c</link>
      <guid>https://dev.to/jefster_farleifernandes/wrappers-in-java-and-spring-boot-what-they-are-when-to-use-and-when-to-create-custom-ones-193c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In Java development, especially in Spring Boot applications, wrappers play a crucial role in enhancing functionality, improving security, ensuring thread safety, and simplifying complex operations. While Java provides a robust collection framework and utility classes, there are cases where custom wrappers become essential.&lt;/p&gt;

&lt;p&gt;This article explores what wrappers are, when to use them, and how to create custom ones tailored for real-world applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Are Wrappers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A wrapper is a design pattern that encapsulates an existing object or collection, adding additional functionality without modifying the original implementation. Wrappers are commonly used for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read-only access (e.g., Collections.unmodifiableList)&lt;/li&gt;
&lt;li&gt;Thread safety (e.g., Collections.synchronizedList)&lt;/li&gt;
&lt;li&gt;Logging and debugging&lt;/li&gt;
&lt;li&gt;Caching and performance optimization&lt;/li&gt;
&lt;li&gt;Event-driven behavior (e.g., observable collections)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;When to Use Wrappers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrappers are beneficial when:&lt;/li&gt;
&lt;li&gt;Enhancing an existing collection or object without modifying its source code.&lt;/li&gt;
&lt;li&gt;Implementing additional behaviors like logging, validation, or event notifications.&lt;/li&gt;
&lt;li&gt;Ensuring security by restricting modifications to sensitive data.&lt;/li&gt;
&lt;li&gt;Improving thread safety in concurrent applications.&lt;/li&gt;
&lt;li&gt;Providing default values or error handling mechanisms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common Use Cases in Spring Boot Applications&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Spring Boot applications often require custom wrappers to handle specific concerns. Some common scenarios include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Thread-Safe Wrappers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Spring Boot applications often work in multi-threaded environments. Wrapping collections with synchronization mechanisms ensures safe concurrent access.&lt;/p&gt;

&lt;p&gt;Example: A thread-safe Map using ReadWriteLock:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.*;
import java.util.concurrent.locks.*;

public class SynchronizedReadWriteMap&amp;lt;K, V&amp;gt; {
    private final Map&amp;lt;K, V&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    public void put(K key, V value) {
        lock.writeLock().lock();
        try {
            map.put(key, value);
        } finally {
            lock.writeLock().unlock();
        }
    }

    public V get(K key) {
        lock.readLock().lock();
        try {
            return map.get(key);
        } finally {
            lock.readLock().unlock();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Logging and Auditing Wrappers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Logging wrappers help track modifications to collections, useful for debugging or auditing.&lt;/p&gt;

&lt;p&gt;Example: A logging wrapper for List:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.*;

public class LoggingList&amp;lt;T&amp;gt; extends ArrayList&amp;lt;T&amp;gt; {
    @Override
    public boolean add(T t) {
        System.out.println("Adding element: " + t);
        return super.add(t);
    }

    @Override
    public boolean remove(Object o) {
        System.out.println("Removing element: " + o);
        return super.remove(o);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Read-Only Wrappers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To prevent modifications to a collection, an unmodifiable wrapper ensures data integrity.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.*;

public class UnmodifiableWrapper&amp;lt;T&amp;gt; extends ArrayList&amp;lt;T&amp;gt; {
    @Override
    public boolean add(T t) {
        throw new UnsupportedOperationException("Modification is not allowed");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Observable Wrappers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Observable wrappers notify listeners when data changes, useful for reactive applications.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.*;

public class ObservableMap&amp;lt;K, V&amp;gt; extends HashMap&amp;lt;K, V&amp;gt; {
    private final List&amp;lt;Runnable&amp;gt; listeners = new ArrayList&amp;lt;&amp;gt;();

    public void addListener(Runnable listener) {
        listeners.add(listener);
    }

    private void notifyListeners() {
        for (Runnable listener : listeners) {
            listener.run();
        }
    }

    @Override
    public V put(K key, V value) {
        V result = super.put(key, value);
        notifyListeners();
        return result;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Auto-Expiring Cache Wrappers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For caching, a wrapper can remove entries after a certain time.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.*;
import java.util.concurrent.*;

public class ExpiringCache&amp;lt;K, V&amp;gt; {
    private final Map&amp;lt;K, V&amp;gt; cache = new ConcurrentHashMap&amp;lt;&amp;gt;();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public void put(K key, V value, long expirationTime, TimeUnit unit) {
        cache.put(key, value);
        scheduler.schedule(() -&amp;gt; cache.remove(key), expirationTime, unit);
    }

    public V get(K key) {
        return cache.get(key);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to Create Custom Wrappers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While Java provides built-in wrappers like&lt;code&gt;Collections.synchronizedList&lt;/code&gt; and &lt;code&gt;Collections.unmodifiableMap&lt;/code&gt;, creating custom wrappers is useful when:&lt;/p&gt;

&lt;p&gt;You need business-specific behavior (e.g., access control on collections).&lt;/p&gt;

&lt;p&gt;You require event-driven changes (e.g., auto-updating UI components in Spring Boot with WebSockets).&lt;/p&gt;

&lt;p&gt;You must optimize performance (e.g., batching writes to a database).&lt;/p&gt;

&lt;p&gt;You want to implement retry mechanisms (e.g., handling network failures in REST clients).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wrappers are a powerful tool in Java and Spring Boot applications, enabling better modularity, security, and performance. Whether making collections thread-safe, adding observability, or implementing caching, custom wrappers can significantly improve your application's maintainability.&lt;/p&gt;

&lt;p&gt;By understanding when and how to use them, you can enhance your software design and build more resilient applications. 🚀&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>development</category>
      <category>basic</category>
    </item>
  </channel>
</rss>
