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:
- Create a standard .gitlab-ci.yml file in your repository.
- Write a script within the pipeline that uses cURL to post to your project via the GitLab API
- Schedule it using Gitlab’s scheduled pipelines
You’ll need to also:
- Create a personal access token with the
API
scope - Add it as a CI/CD variable and ensure it is
masked
for security
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
- 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. jq
Is Essential for JSON Handling – Since GitLab’s API expects properly formatted JSON, jq is essential for building and escaping multi-line descriptions.- 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!