curl --request PATCH \
--url https://api.trunk.io/v2/dynamic-ci/paths-filters \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"repo": {
"owner": "acme",
"name": "widgets",
"host": "github.com"
},
"overwrite": false,
"filters": [
{
"rules": {
"include": [
{
"glob": "web/**"
}
],
"exclude": [
{
"glob": "web/**/*.md"
}
]
},
"jobs": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit"
}
],
"name": "web"
}
],
"clear": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit"
}
]
}
'import requests
url = "https://api.trunk.io/v2/dynamic-ci/paths-filters"
payload = {
"repo": {
"owner": "acme",
"name": "widgets",
"host": "github.com"
},
"overwrite": False,
"filters": [
{
"rules": {
"include": [{ "glob": "web/**" }],
"exclude": [{ "glob": "web/**/*.md" }]
},
"jobs": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit"
}
],
"name": "web"
}
],
"clear": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
repo: {owner: 'acme', name: 'widgets', host: 'github.com'},
overwrite: false,
filters: [
{
rules: {include: [{glob: 'web/**'}], exclude: [{glob: 'web/**/*.md'}]},
jobs: [{workflowPath: '.github/workflows/ci.yaml', jobKey: 'web-unit'}],
name: 'web'
}
],
clear: [{workflowPath: '.github/workflows/ci.yaml', jobKey: 'web-unit'}]
})
};
fetch('https://api.trunk.io/v2/dynamic-ci/paths-filters', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.trunk.io/v2/dynamic-ci/paths-filters",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'repo' => [
'owner' => 'acme',
'name' => 'widgets',
'host' => 'github.com'
],
'overwrite' => false,
'filters' => [
[
'rules' => [
'include' => [
[
'glob' => 'web/**'
]
],
'exclude' => [
[
'glob' => 'web/**/*.md'
]
]
],
'jobs' => [
[
'workflowPath' => '.github/workflows/ci.yaml',
'jobKey' => 'web-unit'
]
],
'name' => 'web'
]
],
'clear' => [
[
'workflowPath' => '.github/workflows/ci.yaml',
'jobKey' => 'web-unit'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.trunk.io/v2/dynamic-ci/paths-filters"
payload := strings.NewReader("{\n \"repo\": {\n \"owner\": \"acme\",\n \"name\": \"widgets\",\n \"host\": \"github.com\"\n },\n \"overwrite\": false,\n \"filters\": [\n {\n \"rules\": {\n \"include\": [\n {\n \"glob\": \"web/**\"\n }\n ],\n \"exclude\": [\n {\n \"glob\": \"web/**/*.md\"\n }\n ]\n },\n \"jobs\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ],\n \"name\": \"web\"\n }\n ],\n \"clear\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ]\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.trunk.io/v2/dynamic-ci/paths-filters")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"repo\": {\n \"owner\": \"acme\",\n \"name\": \"widgets\",\n \"host\": \"github.com\"\n },\n \"overwrite\": false,\n \"filters\": [\n {\n \"rules\": {\n \"include\": [\n {\n \"glob\": \"web/**\"\n }\n ],\n \"exclude\": [\n {\n \"glob\": \"web/**/*.md\"\n }\n ]\n },\n \"jobs\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ],\n \"name\": \"web\"\n }\n ],\n \"clear\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.trunk.io/v2/dynamic-ci/paths-filters")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"repo\": {\n \"owner\": \"acme\",\n \"name\": \"widgets\",\n \"host\": \"github.com\"\n },\n \"overwrite\": false,\n \"filters\": [\n {\n \"rules\": {\n \"include\": [\n {\n \"glob\": \"web/**\"\n }\n ],\n \"exclude\": [\n {\n \"glob\": \"web/**/*.md\"\n }\n ]\n },\n \"jobs\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ],\n \"name\": \"web\"\n }\n ],\n \"clear\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"filters": [
{
"pathsFilterId": "e8f1c2a4-5b6d-4e7f-8a9b-0c1d2e3f4a5b",
"name": "web",
"status": "new",
"jobCount": 1
}
],
"jobs": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit",
"status": "set",
"jobIds": [
"3c4d0b17-8e2a-4f6c-9d1b-7a5e3c2f1d0e"
]
}
]
}Set or clear paths filters on jobs
Requires the Update Dynamic CI settings permission.
Sets a paths filter on each job named in filters, and removes it from each job in clear. Name a job by its workflow file and its key under jobs:. Each filter applies to pull requests and the merge queue alike. A request names at most 500 jobs in all, across every filters[].jobs and clear.
It changes only the jobs it names. It never deletes a filter; one the request leaves with no jobs stays in the list, with no jobs. Sending the same body again changes nothing, so no Idempotency-Key is needed. A job that already has a different filter fails the request with PATHS_FILTER_CONFLICT unless overwrite is true. Any error means nothing was written.
curl --request PATCH \
--url https://api.trunk.io/v2/dynamic-ci/paths-filters \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"repo": {
"owner": "acme",
"name": "widgets",
"host": "github.com"
},
"overwrite": false,
"filters": [
{
"rules": {
"include": [
{
"glob": "web/**"
}
],
"exclude": [
{
"glob": "web/**/*.md"
}
]
},
"jobs": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit"
}
],
"name": "web"
}
],
"clear": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit"
}
]
}
'import requests
url = "https://api.trunk.io/v2/dynamic-ci/paths-filters"
payload = {
"repo": {
"owner": "acme",
"name": "widgets",
"host": "github.com"
},
"overwrite": False,
"filters": [
{
"rules": {
"include": [{ "glob": "web/**" }],
"exclude": [{ "glob": "web/**/*.md" }]
},
"jobs": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit"
}
],
"name": "web"
}
],
"clear": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
repo: {owner: 'acme', name: 'widgets', host: 'github.com'},
overwrite: false,
filters: [
{
rules: {include: [{glob: 'web/**'}], exclude: [{glob: 'web/**/*.md'}]},
jobs: [{workflowPath: '.github/workflows/ci.yaml', jobKey: 'web-unit'}],
name: 'web'
}
],
clear: [{workflowPath: '.github/workflows/ci.yaml', jobKey: 'web-unit'}]
})
};
fetch('https://api.trunk.io/v2/dynamic-ci/paths-filters', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.trunk.io/v2/dynamic-ci/paths-filters",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'repo' => [
'owner' => 'acme',
'name' => 'widgets',
'host' => 'github.com'
],
'overwrite' => false,
'filters' => [
[
'rules' => [
'include' => [
[
'glob' => 'web/**'
]
],
'exclude' => [
[
'glob' => 'web/**/*.md'
]
]
],
'jobs' => [
[
'workflowPath' => '.github/workflows/ci.yaml',
'jobKey' => 'web-unit'
]
],
'name' => 'web'
]
],
'clear' => [
[
'workflowPath' => '.github/workflows/ci.yaml',
'jobKey' => 'web-unit'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.trunk.io/v2/dynamic-ci/paths-filters"
payload := strings.NewReader("{\n \"repo\": {\n \"owner\": \"acme\",\n \"name\": \"widgets\",\n \"host\": \"github.com\"\n },\n \"overwrite\": false,\n \"filters\": [\n {\n \"rules\": {\n \"include\": [\n {\n \"glob\": \"web/**\"\n }\n ],\n \"exclude\": [\n {\n \"glob\": \"web/**/*.md\"\n }\n ]\n },\n \"jobs\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ],\n \"name\": \"web\"\n }\n ],\n \"clear\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ]\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.trunk.io/v2/dynamic-ci/paths-filters")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"repo\": {\n \"owner\": \"acme\",\n \"name\": \"widgets\",\n \"host\": \"github.com\"\n },\n \"overwrite\": false,\n \"filters\": [\n {\n \"rules\": {\n \"include\": [\n {\n \"glob\": \"web/**\"\n }\n ],\n \"exclude\": [\n {\n \"glob\": \"web/**/*.md\"\n }\n ]\n },\n \"jobs\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ],\n \"name\": \"web\"\n }\n ],\n \"clear\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.trunk.io/v2/dynamic-ci/paths-filters")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"repo\": {\n \"owner\": \"acme\",\n \"name\": \"widgets\",\n \"host\": \"github.com\"\n },\n \"overwrite\": false,\n \"filters\": [\n {\n \"rules\": {\n \"include\": [\n {\n \"glob\": \"web/**\"\n }\n ],\n \"exclude\": [\n {\n \"glob\": \"web/**/*.md\"\n }\n ]\n },\n \"jobs\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ],\n \"name\": \"web\"\n }\n ],\n \"clear\": [\n {\n \"workflowPath\": \".github/workflows/ci.yaml\",\n \"jobKey\": \"web-unit\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"filters": [
{
"pathsFilterId": "e8f1c2a4-5b6d-4e7f-8a9b-0c1d2e3f4a5b",
"name": "web",
"status": "new",
"jobCount": 1
}
],
"jobs": [
{
"workflowPath": ".github/workflows/ci.yaml",
"jobKey": "web-unit",
"status": "set",
"jobIds": [
"3c4d0b17-8e2a-4f6c-9d1b-7a5e3c2f1d0e"
]
}
]
}Authorizations
An API key, sent as Authorization: Bearer <key>. An organization admin creates one in the Trunk app under Settings → Developer → API Keys and chooses the permissions it holds. A key with none can read merge queues but change nothing in them. Permissions cover merge queues and test-result uploads, including the quarantine lookups a CI run makes before it uploads; any key can call the other Flaky Tests and Dynamic CI endpoints, including their writes.
Body
Show child attributes
Show child attributes
Replace a different filter already on a job. Without it, such a job fails the request with PATHS_FILTER_CONFLICT.
false
100Show child attributes
Show child attributes
Jobs to remove the paths filter from.
500A job, as { workflowPath, jobKey } or as { jobId }.
- Option 1
- Option 2
Show child attributes
Show child attributes
Response
What the request did to each job
Was this page helpful?