top of page
Daniel Gorski

Minimize Conflicts in a multi-project repo with GitHub Workflows

How to Manage Multiple Business Central Apps in a Single GitHub Repo with Workflows 🚀


Managing multiple apps for Microsoft Business Central in a single GitHub repository can seem challenging at first, but with the right tools and workflows, it becomes super easy and efficient! In this blog, I'll walk you through how to handle multiple apps in one repo, detect conflicts in app ranges, and automatically update your README.md using a GitHub workflow. Let’s dive right in! 💡

Do you want an autoupdated readme like that one?


Why Use One Repo for Multiple Business Central Apps? 🤔


Keeping multiple Business Central apps in one repository allows you to:


  1. Streamline your workflow: Manage all apps from one central location.

  2. Collaborate more effectively: Teams can work on different apps within the same project.

  3. Reduce repo clutter: No need to maintain a separate repository for each app.


However, it can get tricky when apps have overlapping object ranges, especially when apps need to use different sections of the Business Central range. But don’t worry—GitHub workflows can automate the process of checking for these overlaps! 👨‍💻👩‍💻


Automating Conflict Detection with GitHub Workflows ⚙️


GitHub workflows can automate your repository tasks, like checking for app range conflicts and updating documentation. Below is an example workflow that detects conflicts between multiple Business Central apps and helps you maintain control over their from and to ranges. 🚨


This is also available on our demo showcase in our GitHub Organization: https://github.com/byndit/PTE-Readme-Workflow


Step 1: Set Up Your GitHub Workflow

Create a .github/workflows/update-readme.yml file in your repo. This workflow will:

  • Generate a table of apps and their object ranges.

  • Check for conflicts where two apps might use overlapping object ranges.

  • Update the README.md with the app information and flag any conflicts with an emoji! ⚠️

name: Update README with Table

on:
  push:
    branches:
      - main
  workflow_dispatch: # Allows manual triggering of the workflow

jobs:
  update-readme:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2

    - name: Set up Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '14'

    - name: Generate repository folder information
      id: generate_table
      run: |
        # Set the starting "from" value at 50000 and maximum at 99999
        START_FROM=50000
        MAX_TO=99999

        # Create an empty array to store the rows and a list to track used ranges
        ROWS=()
        DECLARED_RANGES=()

        # Generate and sort rows on the fly
        mapfile -t SORTED_ROWS < <(
          find . -maxdepth 2 -type f -name "app.json" -exec dirname {} \; | while IFS= read -r folder; do
            # Extract "from", "to", and "name" values from app.json
            FROM=$(grep -m 1 '"from":' "$folder/app.json" | sed 's/[^0-9]*//g')
            TO=$(grep -m 1 '"to":' "$folder/app.json" | sed 's/[^0-9]*//g')
            NAME=$(grep -m 1 '"name":' "$folder/app.json" | sed 's/.*"name": "\(.*\)".*/\1/')
            
            if [ "$FROM" ] && [ "$TO" ] && [ "$NAME" ]; then
              # Print each row for sorting
              echo "$FROM:$TO:$NAME"
            fi
          done | sort -t':' -k1,1n
        )

        # Start building the table, keeping track of gaps
        TABLE="| App | From | To | Conflict |\n|------------------------------------|--------|--------|-----------|"
        
        # Initialize the previous "to" to the starting point 50000
        PREV_TO=$((START_FROM - 1))

        # Function to check if ranges overlap
        overlap() {
          local range_from=$1
          local range_to=$2
          local existing_from=$3
          local existing_to=$4

          # Check if ranges overlap
          if [ "$range_from" -le "$existing_to" ] && [ "$range_to" -ge "$existing_from" ]; then
            return 0  # Overlap found
          else
            return 1  # No overlap
          fi
        }

        for row in "${SORTED_ROWS[@]}"; do
          FROM=$(echo "$row" | cut -d':' -f1)
          TO=$(echo "$row" | cut -d':' -f2)
          NAME=$(echo "$row" | cut -d':' -f3)

          # Conflict detection for range overlap
          CONFLICT=""
          for declared_range in "${DECLARED_RANGES[@]}"; do
            DECLARED_FROM=$(echo "$declared_range" | cut -d':' -f1)
            DECLARED_TO=$(echo "$declared_range" | cut -d':' -f2)
            if overlap "$FROM" "$TO" "$DECLARED_FROM" "$DECLARED_TO"; then
              CONFLICT="⚠️"
              break
            fi
          done

          # Add the current range to the declared ranges list
          DECLARED_RANGES+=("$FROM:$TO")

          # Check if there is a gap between the previous "to" and current "from"
          if [ "$PREV_TO" -lt "$((FROM - 1))" ]; then
            GAP_FROM=$((PREV_TO + 1))
            GAP_TO=$((FROM - 1))
            # Add an empty row for the gap
            TABLE+="\n| (empty) | $GAP_FROM | $GAP_TO | |"
          fi

          # Add the current row with conflict info
          TABLE+="\n| $NAME | $FROM | $TO | $CONFLICT |"
          
          # Update PREV_TO
          PREV_TO=$TO
        done

        # Check if there's a gap between the last "to" and the maximum (99999)
        if [ "$PREV_TO" -lt "$MAX_TO" ]; then
          GAP_FROM=$((PREV_TO + 1))
          GAP_TO=$MAX_TO
          TABLE+="\n| (empty) | $GAP_FROM | $GAP_TO | |"
        fi

        # Write the table to table.md
        echo -e "$TABLE" > table.md
        cat table.md
      shell: bash

    - name: Create README.md if not exists
      run: |
        if [ ! -f README.md ]; then
          # Use echo -e to interpret \n as new lines
          echo -e "# This project contains several PTE modules." > README.md
        fi

    - name: Update README.md with placeholder
      run: |
        # Log the current state of README.md for troubleshooting
        echo "Current README.md before update:"
        cat README.md

        # Remove the old table (from start_table comment to end_table comment) and insert placeholder
        sed -i '/\[comment\]: <> (start_table)/,/\[comment\]: <> (end_table)/c [TABLE_PLACEHOLDER]' README.md
        
        # Verify if the placeholder has been inserted
        echo "README.md after inserting placeholder:"
        cat README.md
        
        # Insert the new table with the start and end comments around the placeholder
        sed -i '/\[TABLE_PLACEHOLDER\]/{
          a [comment]: <> (start_table)\n
          r table.md
          a \\
          a [comment]: <> (end_table)
          d
        }' README.md
        
        # Log the updated README.md to check if changes are made
        echo "README.md after updating table:"
        cat README.md
        
        # Forcefully stage README.md for commit
        git add README.md
        git diff --cached
        
        # Check if any changes have been made
        git status

    - name: Check if README.md has changed
      id: check_diff
      run: |
        # Check if README.md has changes
        git diff --exit-code README.md || echo "README.md has been modified"

    - name: Commit and push changes if README.md has changed
      if: steps.check_diff.outcome == 'success'
      run: |
        git config --local user.email "github-actions[bot]@users.noreply.github.com"
        git config --local user.name "GitHub Actions Bot"
        git commit -m "Update README.md with generated table" || echo "No changes to commit"
        git push || echo "Nothing to push"
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

How This Workflow Works 🛠️


  1. Detect App Ranges: The workflow loops through each app's app.json file to extract the from, to, and name values. These values are then stored in a list.


  2. Check for Overlaps: The overlap function compares each app’s range with previously declared ranges. If any range overlaps with another app’s range, a conflict marker (⚠️) is added to the table.


  3. Auto-update README: After processing, the table is inserted into your README.md file between predefined comment markers ([comment]: <> (start_table) and [comment]: <> (end_table)). This ensures that the table is always up to date.


Handling App Conflicts Easily ⚠️


Having multiple apps in a Business Central repo can lead to conflicts in object ranges, but with this workflow:

  • You get automatic detection of conflicts between apps.

  • The conflict is marked in your README file with a ⚠️ emoji so it's easy to spot potential issues.

  • You’ll know exactly which app ranges need adjustment before deployment!


Keeping Your Team on the Same Page 🤝


Managing multiple apps in one repo is a smart way to streamline Business Central development, but staying organized is key! By using GitHub workflows, you can:

  • Automate documentation: Keep your repo up to date without manual editing.

  • Prevent app conflicts: The workflow handles range checking, so no more manual checks!

  • Collaborate seamlessly: Ensure everyone on the team knows what ranges are in use and where conflicts exist.


Final Thoughts 💬


With this GitHub workflow, managing multiple Business Central apps becomes a breeze! You can easily prevent conflicts, update your documentation, and keep everything running smoothly. 🚀


Now that you know how to manage multiple Business Central apps in one repo with ease, it’s time to put this into practice! 👨‍💻👩‍💻


Do you have any other Business Central challenges you'd like to automate? Let me know in the comments! 💬


Happy coding! ✨

81 Ansichten0 Kommentare

Aktuelle Beiträge

Alle ansehen

Comments


bottom of page