ServiceNow-AI/gitlab-tasks huggingface dataset:
Task: gitlab.create-pr
Goal: Submit a merge request in the a11yproject/a11yproject.com repo for redesign branch to be merged into main branch, assign Roshan Jossy as the reviewer
Task configuration:
namespace: a11yproject
project_name: a11yproject.com
source_branch: redesign
target_branch: main
reviewer: Roshan Jossy

Validation code:
from typing import Any, Dict, List
from urllib.parse import quote

import requests
import json
import os

def _get_headers():
    return {
        "Content-Type": "application/json",
        "Accept": "application/json",
        **json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}")),
    }

def _get_current_user():
    url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user"
    response = requests.get(url=url, headers=_get_headers())
    if response.status_code == 200:
        return response.json()
    return None

def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    # Check whether we have the necessary information to validate
    if (
        not "namespace" in config
        or not "project_name" in config
        or not "source_branch" in config
        or not "target_branch" in config
    ):
        raise ValueError(
            "Target must contain 'namespace', 'project_name', 'source_branch' and 'target_branch'"
        )

    # check whether we have messages
    if not messages:
        raise ValueError("Messages are empty")

    project_id = quote(f"{config['namespace']}/{config['project_name']}", safe="")

    url = (
        os.getenv("GITLAB_BASE_URL", "").rstrip("/")
        + "/api/v4/projects/"
        + project_id
        + "/merge_requests"
        + "?source_branch="
        + config["source_branch"]
        + "&target_branch="
        + config["target_branch"]
    )

    response = requests.get(url=url, headers=_get_headers())
    if response.status_code != 200:
        return 0
    result = response.json()

    if len(result) == 0:
        return 0
    result = result[0]

    if "reviewer" in config:
        reviewer_value = config["reviewer"].lower().strip()

        # Handle "myself" as reviewer
        if reviewer_value == "myself":
            current_user = _get_current_user()
            if current_user is None:
                return 0
            for elem in result["reviewers"]:
                if (current_user["username"].lower() in elem["username"].lower()
                    or current_user["name"].lower() in elem["name"].lower()):
                    return 1
            return 0
        else:
            for elem in result["reviewers"]:
                if (reviewer_value in elem["name"].lower()
                    or reviewer_value in elem["username"].lower()):
                    return 1
            return 0

    # default: do not check if we need reviewers
    return 1
Task: gitlab.create-pr
Goal: Submit a merge request in the a11yproject/a11yproject.com repo for redesign branch to be merged into markdown-figure-block branch, assign myself as the reviewer
Task configuration:
namespace: a11yproject
project_name: a11yproject.com
source_branch: redesign
target_branch: markdown-figure-block
reviewer: myself

Validation code:
from typing import Any, Dict, List
from urllib.parse import quote

import requests
import json
import os

def _get_headers():
    return {
        "Content-Type": "application/json",
        "Accept": "application/json",
        **json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}")),
    }

def _get_current_user():
    url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user"
    response = requests.get(url=url, headers=_get_headers())
    if response.status_code == 200:
        return response.json()
    return None

def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    # Check whether we have the necessary information to validate
    if (
        not "namespace" in config
        or not "project_name" in config
        or not "source_branch" in config
        or not "target_branch" in config
    ):
        raise ValueError(
            "Target must contain 'namespace', 'project_name', 'source_branch' and 'target_branch'"
        )

    # check whether we have messages
    if not messages:
        raise ValueError("Messages are empty")

    project_id = quote(f"{config['namespace']}/{config['project_name']}", safe="")

    url = (
        os.getenv("GITLAB_BASE_URL", "").rstrip("/")
        + "/api/v4/projects/"
        + project_id
        + "/merge_requests"
        + "?source_branch="
        + config["source_branch"]
        + "&target_branch="
        + config["target_branch"]
    )

    response = requests.get(url=url, headers=_get_headers())
    if response.status_code != 200:
        return 0
    result = response.json()

    if len(result) == 0:
        return 0
    result = result[0]

    if "reviewer" in config:
        reviewer_value = config["reviewer"].lower().strip()

        # Handle "myself" as reviewer
        if reviewer_value == "myself":
            current_user = _get_current_user()
            if current_user is None:
                return 0
            for elem in result["reviewers"]:
                if (current_user["username"].lower() in elem["username"].lower()
                    or current_user["name"].lower() in elem["name"].lower()):
                    return 1
            return 0
        else:
            for elem in result["reviewers"]:
                if (reviewer_value in elem["name"].lower()
                    or reviewer_value in elem["username"].lower()):
                    return 1
            return 0

    # default: do not check if we need reviewers
    return 1
Task: gitlab.create-pr
Goal: Submit a merge request in the primer/design repo for debug-build-time branch to be merged into dialog branch, assign myself as the reviewer
Task configuration:
namespace: primer
project_name: design
source_branch: debug-build-time
target_branch: dialog
reviewer: myself

Validation code:
from typing import Any, Dict, List
from urllib.parse import quote

import requests
import json
import os

def _get_headers():
    return {
        "Content-Type": "application/json",
        "Accept": "application/json",
        **json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}")),
    }

def _get_current_user():
    url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user"
    response = requests.get(url=url, headers=_get_headers())
    if response.status_code == 200:
        return response.json()
    return None

def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    # Check whether we have the necessary information to validate
    if (
        not "namespace" in config
        or not "project_name" in config
        or not "source_branch" in config
        or not "target_branch" in config
    ):
        raise ValueError(
            "Target must contain 'namespace', 'project_name', 'source_branch' and 'target_branch'"
        )

    # check whether we have messages
    if not messages:
        raise ValueError("Messages are empty")

    project_id = quote(f"{config['namespace']}/{config['project_name']}", safe="")

    url = (
        os.getenv("GITLAB_BASE_URL", "").rstrip("/")
        + "/api/v4/projects/"
        + project_id
        + "/merge_requests"
        + "?source_branch="
        + config["source_branch"]
        + "&target_branch="
        + config["target_branch"]
    )

    response = requests.get(url=url, headers=_get_headers())
    if response.status_code != 200:
        return 0
    result = response.json()

    if len(result) == 0:
        return 0
    result = result[0]

    if "reviewer" in config:
        reviewer_value = config["reviewer"].lower().strip()

        # Handle "myself" as reviewer
        if reviewer_value == "myself":
            current_user = _get_current_user()
            if current_user is None:
                return 0
            for elem in result["reviewers"]:
                if (current_user["username"].lower() in elem["username"].lower()
                    or current_user["name"].lower() in elem["name"].lower()):
                    return 1
            return 0
        else:
            for elem in result["reviewers"]:
                if (reviewer_value in elem["name"].lower()
                    or reviewer_value in elem["username"].lower()):
                    return 1
            return 0

    # default: do not check if we need reviewers
    return 1
Task: gitlab.create-pr
Goal: Submit a merge request for the branch that adds color utility classes to be merged into redesign branch in repo a11yproject/a11yproject.com, assign myself as the reviewer
Task configuration:
namespace: a11yproject
project_name: a11yproject.com
reviewer: myself
source_branch_nl: the branch that adds color utility classes
source_branch: add-color-utility-classes
target_branch: redesign

Validation code:
from typing import Any, Dict, List
from urllib.parse import quote

import requests
import json
import os

def _get_headers():
    return {
        "Content-Type": "application/json",
        "Accept": "application/json",
        **json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}")),
    }

def _get_current_user():
    url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user"
    response = requests.get(url=url, headers=_get_headers())
    if response.status_code == 200:
        return response.json()
    return None

def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    # Check whether we have the necessary information to validate
    if (
        not "namespace" in config
        or not "project_name" in config
        or not "source_branch" in config
        or not "target_branch" in config
    ):
        raise ValueError(
            "Target must contain 'namespace', 'project_name', 'source_branch' and 'target_branch'"
        )

    # check whether we have messages
    if not messages:
        raise ValueError("Messages are empty")

    project_id = quote(f"{config['namespace']}/{config['project_name']}", safe="")

    url = (
        os.getenv("GITLAB_BASE_URL", "").rstrip("/")
        + "/api/v4/projects/"
        + project_id
        + "/merge_requests"
        + "?source_branch="
        + config["source_branch"]
        + "&target_branch="
        + config["target_branch"]
    )

    response = requests.get(url=url, headers=_get_headers())
    if response.status_code != 200:
        return 0
    result = response.json()

    if len(result) == 0:
        return 0
    result = result[0]

    if "reviewer" in config:
        reviewer_value = config["reviewer"].lower().strip()

        # Handle "myself" as reviewer
        if reviewer_value == "myself":
            current_user = _get_current_user()
            if current_user is None:
                return 0
            for elem in result["reviewers"]:
                if (current_user["username"].lower() in elem["username"].lower()
                    or current_user["name"].lower() in elem["name"].lower()):
                    return 1
            return 0
        else:
            for elem in result["reviewers"]:
                if (reviewer_value in elem["name"].lower()
                    or reviewer_value in elem["username"].lower()):
                    return 1
            return 0

    # default: do not check if we need reviewers
    return 1
Task: gitlab.get-and-update-info
Goal: Set my status to Busy and change the homepage URL on my profile to https://egg.tart.com. Then can you tell me the full names of the repositories where I made contributions and they got at least 20 stars?
Task configuration:
status: Busy
url: https://egg.tart.com
description: at least 20
repos: a11yproject.com, design

Validation code:
from typing import Any, Dict, List
from urllib.parse import quote

import requests
import json
import os

def _get_headers():
    return {
        "Content-Type": "application/json",
        "Accept": "application/json",
        **json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}")),
    }

def _normalize_url(url):
    """Normalize URL for comparison: strip protocol and trailing slashes."""
    url = url.lower().strip().rstrip("/")
    for prefix in ["https://", "http://"]:
        if url.startswith(prefix):
            url = url[len(prefix):]
    return url

def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    if not messages:
        raise ValueError("Messages cannot be empty")
    content = messages[-1].get("content", "")

    # Check whether we have the necessary information to validate
    if not "status" in config or not "url" in config or not "repos" in config:
        raise ValueError("Target must contain 'status', 'url' and 'repos'")

    # Build the url
    status_url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user/status"

    response = requests.get(url=status_url, headers=_get_headers())
    if not response.status_code == 200:
        return 0
    result = response.json()

    # check status first
    # special case: if status is "busy", we can rely on availability to return reward
    if config["status"].lower().strip() == "busy":
        if (
            result["availability"] != "busy"
            or config["status"].lower().strip()
            != (result.get("message") or "").lower().strip()
        ):
            return 0
    elif config["status"].lower().strip() != (result.get("message") or "").lower().strip():
        return 0

    # then check the url
    user_url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user"
    response = requests.get(url=user_url, headers=_get_headers())
    if not response.status_code == 200:
        return 0
    result = response.json()

    # Normalize URLs for comparison (GitLab may add http:// prefix)
    if _normalize_url(result["website_url"]) != _normalize_url(config["url"]):
        return 0

    # finally check the repos
    # repos may be a comma-separated string or a list
    repos = config["repos"]
    if isinstance(repos, str):
        repos = [r.strip() for r in repos.split(",") if r.strip()]
    for repo in repos:
        # we don't penalize for repos that are in the message but should not be there
        if repo not in content:
            return 0

    return 1
Task: gitlab.get-and-update-info
Goal: Set my status to Resting, please do not disturb and change the homepage URL on my profile to https://helloworld.xyz. Then can you tell me the full names of the repositories where I made contributions and they got the most stars?
Task configuration:
status: Resting, please do not disturb
url: https://helloworld.xyz
description: the most
repos: a11y-syntax-highlighting, a11y-webring.club, accessible-html-content-patterns, ericwbailey.website, cloud-to-butt, dotfiles, timeit, solarized-prism-theme, gimmiethat.space, remove-board-movement-events-from-the-github-issue-timeline

Validation code:
from typing import Any, Dict, List
from urllib.parse import quote

import requests
import json
import os

def _get_headers():
    return {
        "Content-Type": "application/json",
        "Accept": "application/json",
        **json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}")),
    }

def _normalize_url(url):
    """Normalize URL for comparison: strip protocol and trailing slashes."""
    url = url.lower().strip().rstrip("/")
    for prefix in ["https://", "http://"]:
        if url.startswith(prefix):
            url = url[len(prefix):]
    return url

def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    if not messages:
        raise ValueError("Messages cannot be empty")
    content = messages[-1].get("content", "")

    # Check whether we have the necessary information to validate
    if not "status" in config or not "url" in config or not "repos" in config:
        raise ValueError("Target must contain 'status', 'url' and 'repos'")

    # Build the url
    status_url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user/status"

    response = requests.get(url=status_url, headers=_get_headers())
    if not response.status_code == 200:
        return 0
    result = response.json()

    # check status first
    # special case: if status is "busy", we can rely on availability to return reward
    if config["status"].lower().strip() == "busy":
        if (
            result["availability"] != "busy"
            or config["status"].lower().strip()
            != (result.get("message") or "").lower().strip()
        ):
            return 0
    elif config["status"].lower().strip() != (result.get("message") or "").lower().strip():
        return 0

    # then check the url
    user_url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user"
    response = requests.get(url=user_url, headers=_get_headers())
    if not response.status_code == 200:
        return 0
    result = response.json()

    # Normalize URLs for comparison (GitLab may add http:// prefix)
    if _normalize_url(result["website_url"]) != _normalize_url(config["url"]):
        return 0

    # finally check the repos
    # repos may be a comma-separated string or a list
    repos = config["repos"]
    if isinstance(repos, str):
        repos = [r.strip() for r in repos.split(",") if r.strip()]
    for repo in repos:
        # we don't penalize for repos that are in the message but should not be there
        if repo not in content:
            return 0

    return 1
Task: gitlab.get-and-update-info
Goal: Set my status to Out of Office and change the homepage URL on my profile to byteblaze.github.io. Then can you tell me the full names of the repositories where I made contributions and they got less than 5 stars?
Task configuration:
status: Out of Office
url: byteblaze.github.io
description: less than 5
repos: a11yproject.com, design

Validation code:
from typing import Any, Dict, List
from urllib.parse import quote

import requests
import json
import os

def _get_headers():
    return {
        "Content-Type": "application/json",
        "Accept": "application/json",
        **json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}")),
    }

def _normalize_url(url):
    """Normalize URL for comparison: strip protocol and trailing slashes."""
    url = url.lower().strip().rstrip("/")
    for prefix in ["https://", "http://"]:
        if url.startswith(prefix):
            url = url[len(prefix):]
    return url

def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    if not messages:
        raise ValueError("Messages cannot be empty")
    content = messages[-1].get("content", "")

    # Check whether we have the necessary information to validate
    if not "status" in config or not "url" in config or not "repos" in config:
        raise ValueError("Target must contain 'status', 'url' and 'repos'")

    # Build the url
    status_url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user/status"

    response = requests.get(url=status_url, headers=_get_headers())
    if not response.status_code == 200:
        return 0
    result = response.json()

    # check status first
    # special case: if status is "busy", we can rely on availability to return reward
    if config["status"].lower().strip() == "busy":
        if (
            result["availability"] != "busy"
            or config["status"].lower().strip()
            != (result.get("message") or "").lower().strip()
        ):
            return 0
    elif config["status"].lower().strip() != (result.get("message") or "").lower().strip():
        return 0

    # then check the url
    user_url = os.getenv("GITLAB_BASE_URL", "").rstrip("/") + "/api/v4/user"
    response = requests.get(url=user_url, headers=_get_headers())
    if not response.status_code == 200:
        return 0
    result = response.json()

    # Normalize URLs for comparison (GitLab may add http:// prefix)
    if _normalize_url(result["website_url"]) != _normalize_url(config["url"]):
        return 0

    # finally check the repos
    # repos may be a comma-separated string or a list
    repos = config["repos"]
    if isinstance(repos, str):
        repos = [r.strip() for r in repos.split(",") if r.strip()]
    for repo in repos:
        # we don't penalize for repos that are in the message but should not be there
        if repo not in content:
            return 0

    return 1
Task: gitlab.get-rss-token
Goal: Get me my RSS feed token
Task configuration:

Validation code:
import re
from typing import Any, Dict, List

import requests
import json
import os


def _get_headers():
    return {
        "Content-Type": "application/json",
        "Accept": "application/json",
        **json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}")),
    }


def _get_toolkit_headers():
    """Headers with only the toolkit auth, not the GitLab backend auth."""
    headers = json.loads(os.getenv("GITLAB_EXTRA_HTTP_HEADERS", "{}"))
    return {
        k: v for k, v in headers.items()
        if "backend" not in k.lower()
    }


def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    if not messages:
        raise ValueError("Messages cannot be empty")

    content = messages[-1].get("content", "")
    base_url = os.getenv("GITLAB_BASE_URL", "").rstrip("/")

    # Extract potential token strings from the agent's output
    # Feed tokens are typically 20+ character alphanumeric strings
    token_candidates = re.findall(r"[a-zA-Z0-9_-]{20,}", content)

    # Try each candidate token against the atom feed
    for token in token_candidates:
        feed_url = base_url + "/dashboard/projects.atom?feed_token=" + token
        response = requests.get(feed_url, headers=_get_toolkit_headers())
        if response.status_code == 200 and "xml" in response.text[:100].lower():
            return 1

    # Fallback: try with full auth headers (the token might be embedded in a URL)
    url_matches = re.findall(r"https?://\S+feed_token=([a-zA-Z0-9_-]+)", content)
    for token in url_matches:
        feed_url = base_url + "/dashboard/projects.atom?feed_token=" + token
        response = requests.get(feed_url, headers=_get_toolkit_headers())
        if response.status_code == 200 and "xml" in response.text[:100].lower():
            return 1

    return 0
Task: gitlab.get-todo
Goal: Check out my todos
Task configuration:

Validation code:
import re
from typing import Any, Dict, List

import os


def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:

    if not messages:
        raise ValueError("Messages cannot be empty")

    content = messages[-1].get("content", "")
    base_url = os.getenv("GITLAB_BASE_URL", "").rstrip("/")

    todos_url = base_url + "/dashboard/todos"
    all_urls = re.findall(r"https?://\S+", content)
    for url in all_urls:
        if url.rstrip("/").startswith(todos_url):
            return 1

    return 0