mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-30 20:48:37 +00:00
- Fix struct field alignment formatting - Add proper error handling for HTTP response writing - Ensure all Go code follows linting standards Signed-off-by: PePe Amengual <2208324+jamengual@users.noreply.github.com>
233 lines
6.9 KiB
Go
233 lines
6.9 KiB
Go
package controllers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/runatlantis/atlantis/server/controllers/web_templates"
|
|
"github.com/runatlantis/atlantis/server/events/models"
|
|
"github.com/runatlantis/atlantis/server/logging"
|
|
)
|
|
|
|
// QueueController handles all requests relating to Atlantis plan queues.
|
|
type QueueController struct {
|
|
AtlantisVersion string `validate:"required"`
|
|
AtlantisURL *url.URL `validate:"required"`
|
|
Logger logging.SimpleLogging `validate:"required"`
|
|
QueueManager models.PlanQueueManager `validate:"required"`
|
|
QueueTemplate web_templates.TemplateWriter `validate:"required"`
|
|
}
|
|
|
|
// QueueData represents the data structure for queue template rendering
|
|
type QueueData struct {
|
|
Queues []QueueInfo
|
|
AtlantisVersion string
|
|
CleanedBasePath string
|
|
}
|
|
|
|
// QueueInfo represents a single queue entry for the UI
|
|
type QueueInfo struct {
|
|
Project string
|
|
Workspace string
|
|
RepoFullName string
|
|
Entries []QueueEntryInfo
|
|
UpdatedAt string
|
|
}
|
|
|
|
// QueueEntryInfo represents a single queue entry for the UI
|
|
type QueueEntryInfo struct {
|
|
ID string
|
|
PullNum int
|
|
Username string
|
|
Time string
|
|
Position int
|
|
}
|
|
|
|
// GetQueues is the GET /queues route. It renders the queue overview page.
|
|
func (q *QueueController) GetQueues(w http.ResponseWriter, r *http.Request) {
|
|
// Get all active queues
|
|
queues, err := q.QueueManager.GetAllQueues()
|
|
if err != nil {
|
|
q.respond(w, logging.Error, http.StatusInternalServerError, "Failed getting queues: %s", err)
|
|
return
|
|
}
|
|
|
|
// Convert to UI-friendly format
|
|
queueInfos := make([]QueueInfo, 0, len(queues))
|
|
for _, queue := range queues {
|
|
entries := make([]QueueEntryInfo, 0, len(queue.Entries))
|
|
for i, entry := range queue.Entries {
|
|
entries = append(entries, QueueEntryInfo{
|
|
ID: entry.ID,
|
|
PullNum: entry.Pull.Num,
|
|
Username: entry.User.Username,
|
|
Time: entry.Time.Format("2006-01-02 15:04:05"),
|
|
Position: i + 1,
|
|
})
|
|
}
|
|
|
|
queueInfos = append(queueInfos, QueueInfo{
|
|
Project: queue.Project.String(),
|
|
Workspace: queue.Workspace,
|
|
RepoFullName: queue.Project.RepoFullName,
|
|
Entries: entries,
|
|
UpdatedAt: queue.UpdatedAt.Format("2006-01-02 15:04:05"),
|
|
})
|
|
}
|
|
|
|
viewData := QueueData{
|
|
Queues: queueInfos,
|
|
AtlantisVersion: q.AtlantisVersion,
|
|
CleanedBasePath: q.AtlantisURL.Path,
|
|
}
|
|
|
|
err = q.QueueTemplate.Execute(w, viewData)
|
|
if err != nil {
|
|
q.Logger.Err(err.Error())
|
|
}
|
|
}
|
|
|
|
// GetQueueStatus is the GET /api/queues/{repo}/{project}/{workspace} route.
|
|
// It returns JSON data for a specific queue.
|
|
func (q *QueueController) GetQueueStatus(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
repoFullName := vars["repo"]
|
|
projectPath := vars["project"]
|
|
workspace := vars["workspace"]
|
|
|
|
project := models.Project{
|
|
RepoFullName: repoFullName,
|
|
Path: projectPath,
|
|
}
|
|
|
|
queue, err := q.QueueManager.GetQueueStatus(project, workspace)
|
|
if err != nil {
|
|
q.respondJSON(w, http.StatusInternalServerError, map[string]string{"error": fmt.Sprintf("Failed getting queue status: %s", err)})
|
|
return
|
|
}
|
|
|
|
if queue == nil {
|
|
q.respondJSON(w, http.StatusNotFound, map[string]string{"error": "Queue not found"})
|
|
return
|
|
}
|
|
|
|
// Convert to JSON-friendly format
|
|
entries := make([]map[string]interface{}, 0, len(queue.Entries))
|
|
for i, entry := range queue.Entries {
|
|
entries = append(entries, map[string]interface{}{
|
|
"id": entry.ID,
|
|
"pull_num": entry.Pull.Num,
|
|
"username": entry.User.Username,
|
|
"time": entry.Time.Format("2006-01-02 15:04:05"),
|
|
"position": i + 1,
|
|
})
|
|
}
|
|
|
|
response := map[string]interface{}{
|
|
"project": queue.Project.String(),
|
|
"workspace": queue.Workspace,
|
|
"entries": entries,
|
|
"updated_at": queue.UpdatedAt.Format("2006-01-02 15:04:05"),
|
|
}
|
|
|
|
q.respondJSON(w, http.StatusOK, response)
|
|
}
|
|
|
|
// RemoveFromQueue is the DELETE /api/queues/{repo}/{project}/{workspace}/{pull_num} route.
|
|
// It removes a specific entry from the queue.
|
|
func (q *QueueController) RemoveFromQueue(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
repoFullName := vars["repo"]
|
|
projectPath := vars["project"]
|
|
workspace := vars["workspace"]
|
|
pullNum := vars["pull_num"]
|
|
|
|
// Parse pull number
|
|
var pullNumInt int
|
|
_, err := fmt.Sscanf(pullNum, "%d", &pullNumInt)
|
|
if err != nil {
|
|
q.respondJSON(w, http.StatusBadRequest, map[string]string{"error": "Invalid pull number"})
|
|
return
|
|
}
|
|
|
|
project := models.Project{
|
|
RepoFullName: repoFullName,
|
|
Path: projectPath,
|
|
}
|
|
|
|
err = q.QueueManager.RemoveFromQueue(project, workspace, pullNumInt)
|
|
if err != nil {
|
|
q.respondJSON(w, http.StatusInternalServerError, map[string]string{"error": fmt.Sprintf("Failed removing from queue: %s", err)})
|
|
return
|
|
}
|
|
|
|
q.respondJSON(w, http.StatusOK, map[string]string{"message": "Successfully removed from queue"})
|
|
}
|
|
|
|
// GetAllQueues is the GET /api/queues route.
|
|
// It returns JSON data for all active queues.
|
|
func (q *QueueController) GetAllQueues(w http.ResponseWriter, r *http.Request) {
|
|
queues, err := q.QueueManager.GetAllQueues()
|
|
if err != nil {
|
|
q.respondJSON(w, http.StatusInternalServerError, map[string]string{"error": fmt.Sprintf("Failed getting queues: %s", err)})
|
|
return
|
|
}
|
|
|
|
// Convert to JSON-friendly format
|
|
queueList := make([]map[string]interface{}, 0, len(queues))
|
|
for _, queue := range queues {
|
|
entries := make([]map[string]interface{}, 0, len(queue.Entries))
|
|
for i, entry := range queue.Entries {
|
|
entries = append(entries, map[string]interface{}{
|
|
"id": entry.ID,
|
|
"pull_num": entry.Pull.Num,
|
|
"username": entry.User.Username,
|
|
"time": entry.Time.Format("2006-01-02 15:04:05"),
|
|
"position": i + 1,
|
|
})
|
|
}
|
|
|
|
queueList = append(queueList, map[string]interface{}{
|
|
"project": queue.Project.String(),
|
|
"workspace": queue.Workspace,
|
|
"repo_full_name": queue.Project.RepoFullName,
|
|
"entries": entries,
|
|
"updated_at": queue.UpdatedAt.Format("2006-01-02 15:04:05"),
|
|
})
|
|
}
|
|
|
|
q.respondJSON(w, http.StatusOK, map[string]interface{}{
|
|
"queues": queueList,
|
|
"count": len(queueList),
|
|
})
|
|
}
|
|
|
|
// respond is a helper function to respond and log the response.
|
|
func (q *QueueController) respond(w http.ResponseWriter, lvl logging.LogLevel, responseCode int, format string, args ...interface{}) {
|
|
response := fmt.Sprintf(format, args...)
|
|
q.Logger.Log(lvl, response)
|
|
w.WriteHeader(responseCode)
|
|
fmt.Fprintln(w, response)
|
|
}
|
|
|
|
// respondJSON is a helper function to respond with JSON data.
|
|
func (q *QueueController) respondJSON(w http.ResponseWriter, responseCode int, data interface{}) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(responseCode)
|
|
|
|
jsonData, err := json.Marshal(data)
|
|
if err != nil {
|
|
q.Logger.Err("Failed to marshal JSON response: %s", err)
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
_, err = w.Write(jsonData)
|
|
if err != nil {
|
|
q.Logger.Err("Failed to write JSON response: %s", err)
|
|
}
|
|
}
|