| 80 | } |
| 81 | |
| 82 | func (lapi *launchpadAPI) SearchTasks(ctx context.Context, project string) ([]LPBug, error) { |
| 83 | var bugs []LPBug |
| 84 | |
| 85 | // First, let us build the URL. Not all statuses are included by |
| 86 | // default, so we have to explicitly enumerate them. |
| 87 | validStatuses := [13]string{ |
| 88 | "New", "Incomplete", "Opinion", "Invalid", |
| 89 | "Won't Fix", "Expired", "Confirmed", "Triaged", |
| 90 | "In Progress", "Fix Committed", "Fix Released", |
| 91 | "Incomplete (with response)", "Incomplete (without response)", |
| 92 | } |
| 93 | queryParams := url.Values{} |
| 94 | queryParams.Add("ws.op", "searchTasks") |
| 95 | queryParams.Add("order_by", "-date_last_updated") |
| 96 | for _, validStatus := range validStatuses { |
| 97 | queryParams.Add("status", validStatus) |
| 98 | } |
| 99 | lpURL := fmt.Sprintf("%s/%s?%s", apiRoot, project, queryParams.Encode()) |
| 100 | |
| 101 | for { |
| 102 | req, err := http.NewRequest("GET", lpURL, nil) |
| 103 | if err != nil { |
| 104 | return nil, err |
| 105 | } |
| 106 | |
| 107 | resp, err := lapi.client.Do(req) |
| 108 | if err != nil { |
| 109 | return nil, err |
| 110 | } |
| 111 | |
| 112 | var result launchpadAnswer |
| 113 | |
| 114 | err = json.NewDecoder(resp.Body).Decode(&result) |
| 115 | _ = resp.Body.Close() |
| 116 | |
| 117 | if err != nil { |
| 118 | return nil, err |
| 119 | } |
| 120 | |
| 121 | for _, bugEntry := range result.Entries { |
| 122 | bug, err := lapi.queryBug(ctx, bugEntry.BugLink) |
| 123 | if err == nil { |
| 124 | bugs = append(bugs, bug) |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | // Launchpad only returns 75 results at a time. We get the next |
| 129 | // page and run another query, unless there is no other page. |
| 130 | lpURL = result.NextLink |
| 131 | if lpURL == "" { |
| 132 | break |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | return bugs, nil |
| 137 | } |
| 138 | |
| 139 | func (lapi *launchpadAPI) queryBug(ctx context.Context, url string) (LPBug, error) { |