[!NOTE|label:reference:]
jira
[!NOTE]
myself
[!NOTE|label:references:]
Copy $ curl -s https://jira.sample.com/rest/api/2/myself
# or via `user?username=<id>`
$ curl -s https://jira.sample.com/rest/api/2/user?username=marslo
get info
Copy # get timezone
$ curl -s https://jira.sample.com/rest/api/2/mypreferences?key=jira.user.timezone
Asia/Shanghai
# get locale
$ curl --request GET \
--url 'https://jira.sample.com/rest/api/2/mypreferences/locale' \
--header 'Accept: application/json'
set info
Copy # set timezone
$ curl --request PUT \
--url 'https://jira.sample.com/rest/api/2/mypreferences?key={key}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '"<string>"'
# set local
$ curl --request PUT \
--url 'https://jira.sample.com/rest/api/2/mypreferences/locale' \
--user 'email@example.com:<api_token>' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{ "locale": "en_US" }'
check fields
Copy $ curl -s \
-k \
-X GET https://${jiraName}/rest/api/2/issue/${jiraID} |
jq --raw-output
check attachment
check attachment ID
Copy $ curl -s \
-k \
-X GET https://${jiraName}/rest/api/2/issue/${jiraID}?fields=attachment |
jq --raw-output .fields.attachment[].id
get attachments download url
Copy $ curl -s \
-k \
-X GET https://${jiraName}/rest/api/2/issue/${jiraID}?fields=attachment |
jq --raw-output .fields.attachment[].content
download all attachments in Jira
-I replace-str Replace occurrences of replace-str in the initial-arguments with names read from standard in- put. Also, unquoted blanks do not terminate input items; instead the separator is the new- line character. Implies -x and -L 1.
Copy $ curl -s \
-k \
-X GET https://${jiraName}/rest/api/2/issue/${jiraID}?fields=attachment |
jq --raw-output .fields.attachment[].content |
xargs -I '{}' curl -sgOJL '{}'
list all projects
Copy $ curl -fsSL -XGET https://jira.sample.com/rest/api/2/project |
jq -r '.[] | [.key, .name] | join(" | ")' |
column -s '|' -t
search issue by JQL
[!TIP]
JQL pattern rule:
project=abc
-> project%3Dabc
%20CONDITION%20
instead of CONDITION
format JQL
[!TIP]
Copy $ jql='project = abc AND issuetype = release order by updated desc'
$ jql=$(printf %s "${jql}" | jq -sRr @uri)
Copy $ jql="$(sed 's/ //g;s/AND/ AND /g;s/OR/ OR /g;s/IN/ IN /g;s/IS/ IS /g' <<< "${jql}")"
$ jql="$(printf %s "${jql}" | jq -sRr @uri)"
# i.e.:
$ jql='project = abc AND issuetype = release'
$ jql="$(sed 's/ //g;s/AND/ AND /g;s/OR/ OR /g;s/IN/ IN /g;s/IS/ IS /g' <<< "${jql}")"
$ echo $jql
project=abc AND issuetype=release
$ jql="$(printf %s "${jql}" | jq -sRr @uri)"
$ echo $jql
project%3Dabc%20AND%20issuetype%3Drelease
api
[!NOTE]
properties
: array<string>
sample: search?jql=${jql}&maxResults=100&startAt=0
Copy $ curl --silent \
--insecure \
--globoff \
--netrc-file ~/.netrc \
-XGET \
"https://jira.sample.com/rest/api/2/search?jql=${jql}" |
jq -r ${jqOpt}
# i.e.:
$ curlOpt='--silent --insecure --globoff --netrc-file ~/.netrc'
$ url='https://jira.sample.com/rest/api/2'
$ queryParams="startAt=0&maxResults=10"
$ jql='project = ABC AND issuetype = Release ORDER BY updated ASC' # copy from Jira website
$ jql="$(printf %s "${jql}" | jq -sRr @uri)"
$ curl "${curlOpt}" "${url}/search?jql=${jql}&${queryParams}" |
jq -r '.issues[]' |
jq -r '. | [.key, .fields.summary, .fields.status.name, .fields.issuetype.name, .fields.updated, .fields.created] | join("|")' |
while IFS='|' read -r _key _summary _status _issuetype _updated _created; do
echo "- [${_key}] - ${_summary}"
echo " - status : ${_status}"
echo " - issuetype : ${_issuetype}"
echo " - created : ${_created}"
echo " - updated : ${_updated}"
done
Copy $ curl --silent \
--insecure \
--globoff \
--netrc-file ~/.netrc \
-XGET \
"https://jira.sample.com/rest/api/2/search?jql=${jql}" |
jq -r ${jqOpt}
# i.e.:
$ curlOpt='--silent --insecure --globoff --netrc-file ~/.netrc'
$ url='https://jira.sample.com/rest/api/2'
$ queryParams="startAt=0&maxResults=10"
$ jql='project = abc AND issuetype = release' # copy from Jira website
$ jql="$(sed 's/ //g;s/AND/ AND /g;s/OR/ OR /g;s/IN/ IN /g;s/IS/ IS /g' <<< "${jql}")"
$ jql="$(printf %s "${jql}" | jq -sRr @uri)"
$ curl "${curlOpt}" "${url}/search?jql=${jql}&${queryParams}" |
jq -r '.issues[]' |
jq -r '. | [.key, .fields.summary, .fields.status.name, .fields.issuetype.name, .fields.updated, .fields.created] | join("|")' |
while IFS='|' read -r _key _summary _status _issuetype _updated _created; do
echo "- [${_key}] - ${_summary}"
echo " - status : ${_status}"
echo " - issuetype : ${_issuetype}"
echo " - created : ${_created}"
echo " - updated : ${_updated}"
done
[get email address](Get Email Addresses For Users)
Copy $ curl GET https://jira.sample.com/rest/api/2/user?key=JIRAUSER10100 |
jq -r
api token
[!NOTE|label:references:]
[!NOTE]
to list all tokens for single user:
Copy $ curl -v -XGET \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/token/ |
jq -r
to list tokens for all users:
Copy $ curl -v \
-X GET \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/tokensByFilter |
jq -r
Copy $ curl -s -D- \
-XGET \
-H "Content-Type: application/json" \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token |
sed '/^\s*$/,$!d;//d' |
jq -r
get id, created, last access, and valid timestamp
Copy function epoch2timestamp() {
[[ 0 != $1 ]] && echo $(date -d @$(( $1/1000 )) +%FT%T.%3N%Z) || echo "0";
}
$ while read -r _id _created _lastAccess _validUntil; do
echo "${_id} $(epoch2timestamp ${_created}) $(epoch2timestamp ${_lastAccess}) $(epoch2timestamp ${_validUntil})";
done < <( curl -s -D- \
-XGET \
-H "Content-Type: application/json" \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token |
sed '/^\s*$/,$!d;//d' |
jq -r '.content[] | [ .id, .created, .lastAccessed, .validUntil ] | join( "\t" )'
) |
column -t
537 2024-01-31T21:32:51.000PST 2024-03-26T23:30:30.000PDT 2024-07-31T21:32:51.000PDT
579 2024-03-26T23:19:16.000PDT 0 2024-09-26T23:19:16.000PDT
# with header
$ ( echo "ID CREATED LASTACCESS VALIDUNTIL";
while read -r _id _created _lastAccess _validUntil; do
echo "${_id} $(epoch2timestamp ${_created}) $(epoch2timestamp ${_lastAccess}) $(epoch2timestamp ${_validUntil})";
done < <( curl -s -D- \
-XGET \
-H "Content-Type: application/json" \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token |
sed '/^\s*$/,$!d;//d' |
jq -r '.content[] | [ .id, .created, .lastAccessed, .validUntil ] | join( "\t" )'
)
) | column -t
ID CREATED LASTACCESS VALIDUNTIL
537 2024-01-31T21:32:51.000PST 2024-03-26T23:33:33.000PDT 2024-07-31T21:32:51.000PDT
579 2024-03-26T23:19:16.000PDT 0 2024-09-26T23:19:16.000PDT
or
Copy $ curl -s -D- \
-XGET \
-H "Content-Type: application/json" \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token |
sed '/^\s*$/,$!d;//d' |
jq -r '.content[] | [ .created, .lastAccessed, .validUntil ] | join("\n")' |
xargs -r -I{} bash -c "et=\"{}\"; date -d @\$(( \${et}/1000 )) +%c"
Mon 18 Dec 2023 10:25:58 AM PST
Tue 26 Mar 2024 10:21:30 PM PDT
Tue 18 Jun 2024 10:25:58 AM PDT
# or
$ while read -r _d; do
date -d @$(( ${_d}/1000 )) +%c;
done < <( curl -s -D- \
-XGET \
-H "Content-Type: application/json" \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token |
sed '/^\s*$/,$!d;//d' |
jq -r '.content[] | [ .created, .lastAccessed, .validUntil ] | join("\n")'
)
Mon 18 Dec 2023 10:25:58 AM PST
Tue 26 Mar 2024 10:14:58 PM PDT
Tue 18 Jun 2024 10:25:58 AM PDT
[!TIP]
expiration keywords
tokenValidityTimeInMonths
tokenExpirationDateTimeMillis
Copy $ curl -v -d '{"tokenDescription":"<token-description>"}' \
-X POST \
--header "Content-Type: application/json" \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/token
create new token with expiration time
[!NOTE|label:references:]
with tokenValidityTimeInMonths
Copy $ curl -v \
-d '{"tokenDescription":"<token-description>", "tokenValidityTimeInMonths" : 1}' \
-X POST \
--header "Content-Type: application/json" \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/token
with tokenExpirationDateTime
Copy $ curl -v \
-d '{"tokenDescription":"Custom expiration", "tokenExpirationDateTime" : "2020-10-19T10:29:00.000+02:00"}' \
-X POST \
--header "Content-Type: application/json" \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/token
Copy $ curl -s \
-d '{"tokenDescription":"marslo-token-api-test", "tokenValidityTimeInMonths" : 6}' \
-X POST \
--header "Content-Type: application/json" \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token |
jq -r .plainTextToken
NdxEToKfDsjUE7tct1ePP6erE1xdDsEAa64BOT
Copy $ curl -v \
-d '{"tokenDescription":"token for another user", "tokenForUserKey":"JIRAUSER10105"}' \
POST \
--header "Content-Type: application/json" \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/token
# or with token validity time
$ curl -v \
-d '{"tokenDescription":"token for another user", "tokenForUserKey":"JIRAUSER10105","tokenValidityTimeInMonths":12}' \
POST \
--header "Content-Type: application/json" \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/token
Copy $ curl -v \
-d '{"tokenDescription":"Updated token description"}' \
-X PATCH \
--header "Content-Type: application/json" \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/token/<token-id>
[!NOTE|label:references:]
Copy $ curl -v \
-X DELETE \
https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/token/<token-id>
Copy # list before token deleted
$ ( echo "ID CREATED LASTACCESS VALIDUNTIL";
while read -r _id _created _lastAccess _validUntil; do
echo "${_id} $(epoch2timestamp ${_created}) $(epoch2timestamp ${_lastAccess}) $(epoch2timestamp ${_validUntil})";
done < <( curl -s -D- \
-XGET \
-H "Content-Type: application/json" \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token |
sed '/^\s*$/,$!d;//d' |
jq -r '.content[] | [ .id, .created, .lastAccessed, .validUntil ] | join( "\t" )'
)
) | column -t
ID CREATED LASTACCESS VALIDUNTIL
537 2024-01-31T21:32:51.000PST 2024-03-26T23:40:02.000PDT 2024-07-31T21:32:51.000PDT
579 2024-03-26T23:19:16.000PDT 0 2024-09-26T23:19:16.000PDT
580 2024-03-26T23:36:02.000PDT 0 2024-09-26T23:36:02.000PDT
581 2024-03-26T23:36:11.000PDT 0 2024-09-26T23:36:11.000PDT
# delete
$ curl -s -D- \
-X DELETE \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token/581
HTTP/2 200
date: Wed, 27 Mar 2024 06:41:06 GMT
content-type: application/json;charset=UTF-8
x-arequestid: 1421x248002x2
x-anodeid: jiraprod5
referrer-policy: strict-origin-when-cross-origin
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: sandbox
strict-transport-security: max-age=31536000
set-cookie: JSESSIONID=731380C1F17B2F9A59E211B0442AAFFB; Path=/; Secure; HttpOnly
x-seraph-loginreason: OK
set-cookie: atlassian.xsrf.token=A8KN-1NAU-M55V-EQSR_1811ae8601112c05430589e686032924599718c9_lin; Path=/; Secure; SameSite=None
x-asessionid: k5q153
x-ausername: marslo
cache-control: no-cache, no-store, no-transform
true
# curl without header
$ curl -s \
-X DELETE \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token/580
true
# verify
$ ( echo "ID CREATED LASTACCESS VALIDUNTIL";
while read -r _id _created _lastAccess _validUntil; do
echo "${_id} $(epoch2timestamp ${_created}) $(epoch2timestamp ${_lastAccess}) $(epoch2timestamp ${_validUntil})";
done < <( curl -s -D- \
-XGET \
-H "Content-Type: application/json" \
https://jira.sample.com/rest/de.resolution.apitokenauth/latest/user/token |
sed '/^\s*$/,$!d;//d' |
jq -r '.content[] | [ .id, .created, .lastAccessed, .validUntil ] | join( "\t" )'
)
) | column -t
ID CREATED LASTACCESS VALIDUNTIL
537 2024-01-31T21:32:51.000PST 2024-03-26T23:44:32.000PDT 2024-07-31T21:32:51.000PDT
579 2024-03-26T23:19:16.000PDT 0 2024-09-26T23:19:16.000PDT
Copy $ curl GET \
https://jira.sample.com/rest/api/2/user?username=some.username |
jq -r
read above how to get a user key for a name or by email address;
if you want to filter for more than one user, repeat that parameter for as many users you want to filter for
string to search for in all token descriptions
tokens not valid anymore after that date/ time in milliseconds
0 = no scope (all pre 1.5.0 tokens), 1 = read-only, 2 = read/ write
Copy $ curl "https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/tokensByFilter?notValidAfter=1688918956972" |
jq -r
# with limit and page
$ curl "https://jira-or-confluence.sample.com/rest/de.resolution.apitokenauth/latest/user/tokensByFilter?page=0&limit=1¬ValidAfter=1688918956972" |
jq -r
[!NOTE|label:references:]
Copy $ openssl genrsa -out jira_privatekey.pem 1024
$ openssl req -newkey rsa:1024 -x509 -key jira_privatekey.pem -out jira_publickey.cer -days 365
$ openssl pkcs8 -topk8 -nocrypt -in jira_privatekey.pem -out jira_privatekey.pcks8
$ openssl x509 -pubkey -noout -in jira_publickey.cer > jira_publickey.pem
icons and priority
priority
[!NOTE|label:references:]
Copy $ for _i in "blocker.png" "blocker.svg" "critical.png" "critical.svg" "high.png" "high.svg" "highest.png" "highest.svg" "low.png" "low.svg" "lowest.png" "lowest.svg" "major.png" "major.svg" "medium.png" "medium.svg" "minor.png" "minor.svg" "trivial.png" "trivial.svg"; do
echo "--> ${_i}"
curl -O https://jira-trigger-plugin.atlassian.net/images/icons/priorities/${_i}
done
confluence
Copy $ confluenceName='confluence.domain.com'
$ pageID='143765713'
Copy $ curl -s https://${confluenceName}/rest/api/user/current | jq -r
get info
Copy $ curl -s -X GET https://${confluenceName}/rest/api/content/${pageID} | jq --raw-output
get space
Copy $ curl -s -X GET https://${confluenceName}/rest/api/content/${pageID} | jq .space.key
get title
Copy $ curl -s -X GET https://${confluenceName}/rest/api/content/${pageID} | jq .title
get page history
Copy $ curl -s -X GET https://${confluenceName}/rest/api/content/${pageID} | jq .version.number
get next version
Copy currentVer=$(curl -s -X GET https://${confluenceName}/rest/api/content/${pageID} | jq .version.number)
newVer=$((currentVer+1))
publish to confluence
[!NOTE|label:references:]
Copy $ url="https://${confluenceName}/rest/api/content/${pageID}"
$ page=$(curl -s ${url})
$ space=$(echo "${page}" | jq .space.key)
$ title=$(echo "${page}" | jq .title)
$ currentVer=$(echo "${page}" | jq .version.number)
$ newVer=$((currentVer+1))
$ cat > a.json << EOF
{
"id": "${pageID}",
"type": "page",
"title": ${title},
"space": {"key": ${space}},
"body": {
"storage": {
"value": "<h1>Hi confluence</h1>",
"representation": "storage"
}
},
"version": {"number":${newVer}}
}
EOF
$ curl -s \
-i \
-X PUT \
-H 'Content-Type: application/json' \
--data "$(cat a.json)" \
https://${confluenceName}/rest/api/content/${pageID}
plugins
insert svg
insert svg image
[!TIP|label:get svg image:]
preview the image and get info from URL : ...&preview=/506105287/513281481/k8s-ha-cluster-stacked-etcd.v3.svg
Copy <img width="800" src="https://ewiki.sample.com/download/attachments/506105287/513281481/k8s-ha-cluster-stacked-etcd.v3.svg">
edit source via
[!TIP|label:references:]
Copy <p><ac:image ac:width="301"><ri:attachment ri:filename="SVG_logo.svg" /></ac:image></p>
CLI
[!NOTE|label:references:]
running with docker images
Copy $ $ docker run -ti bobswiftapps/acli:latest acli -a getClientInfo
# or
$ docker run -ti bobswiftapps/acli:latest /bin/bash
bash-4.4# acli -a getClientInfo
# with env
$ cat .env
examplegear=jira -s https://examplegear.atlassian.net -u anonymous
examplegear_confluence=confluence -s https://examplegear.atlassian.net/wiki -u anonymous
$ docker run --env-file=.env -ti bobswiftapps/acli:latest /bin/bash
bash-5.0# acli $examplegear -a getServerInfo
# or
docker run -e examplegear='jira -s https://examplegear.atlassian.net -u anonymous' -ti bobswiftapps/acli:latest /bin/bash
bash-4.4# acli ${examplegear} -a getServerInfo
# with acli.properties
$ docker run -v ${PWD}/acli.properties:/opt/acli/acli.properties \
-ti bobswiftapps/acli:latest
# or prior to version 11.0.0, use:
$ docker run -v ${PWD}/acli.properties:/opt/atlassian-cli/acli.properties \
-ti bobswiftapps/acli:latest
# or with `ACLI_CONFIG` env
$ docker run -v ${PWD}/acli.properties:/tmp/acli.properties \
-e ACLI_CONFIG=/tmp/acli.properties \
-ti bobswiftapps/acli:latest \
acli -a getServerInfo --outputFormat 2
Copy $ acli system setSecureProperty --name my.secret --secret -
Enter secure value: <secret value prompt>
Secure properties file does not yet exist. Creating...
Enter new secure properties password: <new password prompt>
Confirm secure properties password: <new password prompt>
Secure properties file created.
Value for key 'foo' set in secure properties file.