Drupal Git Blame
Given a code snippet or file reference from a Drupal contrib module or Drupal core, generate the git.drupalcode.org blame URL and fetch commit details via the GitLab API.
Step 1 — Identify the file and line numbers
- Determine the source file path containing the code snippet.
- Identify the exact line number(s) within that file.
- Format:
L11for a single line,L11-L15for a range. Store as$LINES. - If the file path is not provided, infer it from context (namespace, class name, module prefix) or ask the user.
Step 2 — Identify project, version, and relative path
Use the drupal-module-info skill to locate the nearest *.info.yml above the file. Extract:
$MACHINE_NAME— filename stem of the.info.yml(e.g.devel)$PROJECT— theproject:field value; if absent walk up to the parent module's.info.yml(submodules inherit from their parent)$VERSION— theversion:field value
Drupal core files (under web/core or docroot/core):
$PROJECT=drupal$VERSION— fromcomposer show drupal/coreorgrep "const VERSION" web/core/lib/Drupal.php
Dev checkouts where version: reads VERSION — inform the user that blame requires a tagged release and stop.
Compute $RELATIVE_PATH — the file path relative to the project root folder.
Example: web/modules/contrib/devel/src/Foo.php → src/Foo.php
Compute $ENCODED_PATH — URL-encode $RELATIVE_PATH (replace / with %2F).
Example: src/Foo.php → src%2FFoo.php
Version tag formats: 2.1.0 (Drupal 10+) or 8.x-3.4 (legacy). Use the exact string from the .info.yml.
Step 3 — Build the blame browser URL
https://git.drupalcode.org/project/$PROJECT/-/blame/$VERSION/$RELATIVE_PATH?ref_type=tags#$LINES
Example:
https://git.drupalcode.org/project/devel/-/blame/5.4.0/src/DevelDumperPluginManagerInterface.php?ref_type=tags#L11
Present this URL to the user immediately as a clickable link.
Step 4 — Fetch blame data via GitLab API
Check whether $DRUPALORG_GITLAB_TOKEN is set before fetching:
if [ -z "$DRUPALORG_GITLAB_TOKEN" ]; then
echo "WARNING: No token set. API rate limits may apply. Set DRUPALORG_GITLAB_TOKEN for reliable access."
fi
Fetch:
curl -sS \
${DRUPALORG_GITLAB_TOKEN:+--header "PRIVATE-TOKEN: $DRUPALORG_GITLAB_TOKEN"} \
"https://git.drupalcode.org/api/v4/projects/project%2F${PROJECT}/repository/files/${ENCODED_PATH}/blame?ref=${VERSION}"
The API returns an array. Each entry groups consecutive lines sharing the same commit:
{
"commit": {
"id": "<sha>",
"message": "Issue #12345 by user: Fix something\n",
"authored_date": "2016-04-11T21:11:40.000+02:00",
"author_name": "username"
},
"lines": ["line content 1", "line content 2"]
}
Track a running line counter (starting at 1) to map each entry's lines array to actual line numbers.
If the API returns a non-200 response:
- 401 → "Token invalid or expired."
- 403 → "Token lacks read_api scope."
- 404 → "Project or ref not found — check
$PROJECTand$VERSION."
Step 5 — Parse and filter
If fetch-blame.py exists at a known skill path, run it:
python3 fetch-blame.py "$PROJECT" "$ENCODED_PATH" "$VERSION"
Otherwise parse the JSON response directly:
- Build a line-number → commit map from the
linesarrays. - Filter to only commits touching the requested
$LINESrange. - Deduplicate commits (the same commit may cover multiple lines).
Step 6 — Output
1. Summary table:
| Variable | Value |
|---|---|
$PROJECT |
e.g. devel |
$VERSION |
e.g. 5.4.0 |
$RELATIVE_PATH |
e.g. src/DevelDumperPluginManagerInterface.php |
$LINES |
e.g. L11 |
2. Blame URL — already shown in Step 3.
3. Commit details for each unique commit touching the requested line range:
Commit: <first line of commit message>
Author: <author_name>
Date: <YYYY-MM-DD>
URL: https://git.drupalcode.org/project/<PROJECT>/-/commit/<sha>
Lines: <line range(s) this commit covers>
If multiple commits touch the requested range, list all of them in line order.