5 minute read Published: Author: Brian Sharpe
Gitlab , CI/CD , Odoo , Project Management , CRM


At Consensus Enterprises, we use GitLab boards for task management and Odoo as our CRM for business development. Like any organizing tool, one needs to put in the time to keep it structured and actionable or the data within can get stale quickly. As a lean team with swappable roles, we prioritize efficiency and consistent workflow automation so we leveraged GitLab CI/CD to automate issue creation for our Odoo grooming process. Here’s how we built an automated pipeline to generate a structured issue every week.


The Problem: Keeping Odoo Grooming on Track

Manually creating a GitLab issue each week was inefficient and prone to oversight. Our goal was simple: automatically generate a GitLab issue every Monday with a structured checklist to ensure our team reviews stalled, new, and ongoing business development opportunities.


The Solution: GitLab CI/CD Automation

We set up a GitLab pipeline that:

  • Creates a structured GitLab issue every week before our meeting.
  • Assigns the correct users dynamically.
  • Formats the issue description to maintain readability and structure.
  • Runs on a schedule, ensuring it only triggers at the right time.

Here’s how we did it.


Setting Up the GitLab CI/CD Job

The core concept is straightforward:

You’ll need to also:

Here’s what the .gtilab-ci.yml looks like:

Note: The Gitlab pipeline editor is your friend

1. Use a Debian Image and Install Dependencies

GitLab CI/CD runs in containers, so we specified a Debian image and ensured jq and curl were installed:

image: debian:latest  # Ensures jq is available

before_script:
  - apt-get update && apt-get install -y jq curl

jq processes JSON responses from the GitLab API, filtering and transforming the data to extract relevant fields like user IDs for assignees. It also safely formats multi-line text for the issue description, escaping characters as needed. Finally, it constructs the JSON payload for the API request, ensuring correct syntax and preventing errors.

2. Define the Issue Title and Due Date

We could just have a simple static title, but no one wants to manage a board of identical ticket names! So we dynamically generate a formatted title and set the due date for the following Tuesday:

script:
  - export DAY_NUM=$(date '+%-d')
  - |
    case "$DAY_NUM" in 
      1|21|31) DAY_SUFFIX="st" ;; 
      2|22) DAY_SUFFIX="nd" ;; 
      3|23) DAY_SUFFIX="rd" ;; 
      *) DAY_SUFFIX="th" ;; 
    esac
    export DAY_SUFFIX
  - export TITLE="Odoo Grooming - $(date '+%B') ${DAY_NUM}${DAY_SUFFIX}, $(date '+%Y')"
  - export DUE_DATE=$(date -d 'next Tuesday' '+%Y-%m-%d')

3. Construct the Issue Description

We prefer using checkboxes for clarity, but as long as you maintain the syntax structure, go ahead and modify the text as needed. The issue description needs to be multi-line and properly formatted for GitLab’s markdown rendering. Using jq, we embed it safely:

  - export DESCRIPTION="$(jq -n --arg desc \
    "These tasks ensure our pipeline remains healthy and organized. Allocate two hours to this work before our weekly meeting.\n\n\
    - [ ] Review \`STALLED\` items.\n\
      - [ ] Mark \`LOST\` items (Define criteria for lost deals)\n\
      - [ ] Update/Create new \`Activities\` (Prioritize moving stalled items)\n\
    - [ ] Review \`NEW\` items\n\
      - [ ] Mark \`LOST\` items\n\
      - [ ] Update stages\n\
      - [ ] Update/Create new \`Activities\`\n\
    - [ ] Review all other opportunities (\`Prospects\`, \`Qualified\`, \`Proposal\`, \`Negotiation\`)\n\
      - [ ] Mark \`LOST\` or \`WON\` items\n\
      - [ ] Add log notes where necessary\n\
      - [ ] Update stages\n\
      - [ ] Update/Create new \`Activities\`" '$desc')"

4. Assign the Correct Users

In the JSON payload we want to give a properly formatted array of assignees by their ID. eg. [1234567,1234567] We could just write these directly into the script but wanted to be slightly more dynamic here and validate the users are on the project and get their proper IDs.

First we pull out the IDs by user name. Assignees need to be correctly retrieved from the GitLab API. Users added at the group level are not included in the project members list. We needed to fetch them from the right endpoint:

  - |
    export ASSIGNEES="$(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
      "https://gitlab.com/api/v4/groups/YOUR_GROUP_ID/members/all" | \
      jq '[.[] | select(.username=="USER_NAME_1" or .username=="USER_NAME_2") | .id]')"

To ensure proper formatting and avoid breaking the script, we check if ASSIGNEES is empty and set it to an empty JSON array if necessary:

  - |
    if [ -z "$ASSIGNEES" ] || [ "$ASSIGNEES" == "[]" ]; then 
      export ASSIGNEES="[]" 
    fi

5. Send the Issue Creation Request

We then construct the JSON payload and send the issue creation request:

  - |
    export JSON_PAYLOAD="$(jq --compact-output --null-input \
      --arg title "$TITLE" \
      --arg desc "$DESCRIPTION" \
      --arg labels "Odoo, State::01 - To Do" \
      --argjson assignees "$ASSIGNEES" \
      --arg due_date "$DUE_DATE" \
      '{ "title": $title, "description": $desc, "labels": $labels, "assignee_ids": $assignees, "due_date": $due_date }')"
  
  - |
    curl --request POST \
         --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
         --header "Content-Type: application/json" \
         --data "$JSON_PAYLOAD" \
         "https://gitlab.com/api/v4/projects/YOUR_PROJECT_ID/issues"

6. Run on a Schedule

To ensure the job only runs when scheduled, we use:

  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'

Note: this could also be written as a script in your repo that the CI/CD can run.

Once you are done with the file you can schedule it using Gitlab’s scheduled pipelines


Lessons Learned

  1. Fetching Assignees Requires the Right Endpoint – Users added at the group level won’t appear under projects/{id}/members, and vice versa. Ensure you fetch from the correct location.
  2. jq Is Essential for JSON Handling – Since GitLab’s API expects properly formatted JSON, jq is essential for building and escaping multi-line descriptions.
  3. Use a Debian Image and Install Dependencies The default GitLab runner image may not include jq or curl, so specify Debian and install them in before_script.

Conclusion

Automating issue creation in GitLab ensures our Odoo CRM grooming stays on track without requiring manual input. By dynamically generating structured issues, assigning the right users, and running on a schedule, we’ve eliminated a manual task and improved our workflow. Setting up a similar automation in GitLab CI/CD is worth the investment for teams looking to streamline their project management.


The article Automating Gitlab Issue Creation for Weekly Odoo Grooming first appeared on the Consensus Enterprises blog.

We've disabled blog comments to prevent spam, but if you have questions or comments about this post, get in touch!