Repository: prometheus/alertmanager
File: notify/jira/jira.go (Go)

Code before:
		return nil, false, nil
	}

	if issueSearchResult.Total > 1 {
		logger.Warn("more than one issue matched, selecting the most recently resolved", "selected_issue", issueSearchResult.Issues[0].Key)
	}

	return &issueSearchResult.Issues[0], false, nil
}

func (n *Notifier) prepareSearchRequest(jql string) (any, string) {
	requestBody := issueSearch{
		JQL:        jql,
		MaxResults: 2,
		Fields:     []string{"status"},
	}

	// if the API type is datacenter always go for v2
	if n.conf.APIType == "datacenter" {
		searchPath := n.conf.APIURL.JoinPath("/search").String()
		return requestBody, searchPath
	}

	// if the API type is cloud always go for v3
	// if the API type is auto or empty and the URL has an atlassian.net suffix, go for v3
	if n.conf.APIType == "cloud" || (n.conf.APIType == "auto" || n.conf.APIType == "") && strings.HasSuffix(n.conf.APIURL.Host, "atlassian.net") {
		searchPath := strings.Replace(n.conf.APIURL.JoinPath("/search/jql").String(), "/2", "/3", 1)
		return requestBody, searchPath
	}

	// if the API type is auto or empty and the URL does not have an atlassian.net suffix, go for v2
	searchPath := n.conf.APIURL.JoinPath("/search").String()
	return requestBody, searchPath
}

func (n *Notifier) getIssueTransitionByName(ctx context.Context, issueKey, transitionName string) (string, bool, error) {
	path := fmt.Sprintf("issue/%s/transitions", issueKey)

	responseBody, shouldRetry, err := n.doAPIRequest(ctx, http.MethodGet, path, nil)
	if err != nil {
		return "", shouldRetry, err
	}

	var issueTransitions issueTransitions
	err = json.Unmarshal(responseBody, &issueTransitions)
	if err != nil {
		return "", false, err
	}

	for _, issueTransition := range issueTransitions.Transitions {
		if issueTransition.Name == transitionName {

Review comment (refactor):
Based on my other comments, I think `n.conf.APIType` can never be the empty string. Therefore I'd remove this case here.
```suggestion
	if n.conf.APIType == "cloud" || (n.conf.APIType == "auto" && strings.HasSuffix(n.conf.APIURL.Host, "atlassian.net")) {
```
I've added the braces for grouping clarity (not everybody is always directly remembering that `&&` has higher precedence than `||`), but that's my personal opinion.

Code after:
		return nil, false, nil
	}

	if issueSearchResult.Total > 1 {
		logger.Warn("more than one issue matched, selecting the most recently resolved", "selected_issue", issueSearchResult.Issues[0].Key)
	}

	return &issueSearchResult.Issues[0], false, nil
}

// prepareSearchRequest builds the request body and search path for Jira issue search.
//
// Atlassian announced (see https://developer.atlassian.com/changelog/#CHANGE-2046) that
// the legacy /search endpoint is no longer available on Jira Cloud. The replacement
// endpoint (/rest/api/3/search/jql) is currently not available in Jira Data Center.
//
// Selection logic:
//   - If APIType is "datacenter", always use the v2 /search endpoint.
//   - If APIType is "cloud", or if APIType is "auto" and the host ends with
//     "atlassian.net", use the v3 /search/jql endpoint.
//   - Otherwise (APIType is "auto" without an atlassian.net host),
//     use the v2 /search endpoint.
func (n *Notifier) prepareSearchRequest(jql string) (issueSearch, string) {
	requestBody := issueSearch{
		JQL:        jql,
		MaxResults: 2,
		Fields:     []string{"status"},
	}

	if n.conf.APIType == "datacenter" {
		searchPath := n.conf.APIURL.JoinPath("/search").String()
		return requestBody, searchPath
	}

	if n.conf.APIType == "cloud" || n.conf.APIType == "auto" && strings.HasSuffix(n.conf.APIURL.Host, "atlassian.net") {
		searchPath := strings.Replace(n.conf.APIURL.JoinPath("/search/jql").String(), "/2", "/3", 1)
		return requestBody, searchPath
	}

	searchPath := n.conf.APIURL.JoinPath("/search").String()
	return requestBody, searchPath
}

func (n *Notifier) getIssueTransitionByName(ctx context.Context, issueKey, transitionName string) (string, bool, error) {
	path := fmt.Sprintf("issue/%s/transitions", issueKey)

	responseBody, shouldRetry, err := n.doAPIRequest(ctx, http.MethodGet, path, nil)
	if err != nil {
		return "", shouldRetry, err
	}