From 497c934a619d2a7ec8b56bfbe0a9a98f3fc0147e Mon Sep 17 00:00:00 2001 From: Carlos Treminio Date: Sat, 8 Feb 2025 13:08:29 -0600 Subject: [PATCH] :sparkles: Added the Issue Archiving API Resolves #339 --- jira/internal/issue_archive_impl.go | 133 ++++++++++++++++++++++++++++ jira/v2/api_client_impl.go | 4 + jira/v3/api_client_impl.go | 4 + service/jira/archive.go | 66 ++++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 jira/internal/issue_archive_impl.go diff --git a/jira/internal/issue_archive_impl.go b/jira/internal/issue_archive_impl.go new file mode 100644 index 00000000..4369db15 --- /dev/null +++ b/jira/internal/issue_archive_impl.go @@ -0,0 +1,133 @@ +package internal + +import ( + "context" + "fmt" + model "github.com/ctreminiom/go-atlassian/v2/pkg/infra/models" + "github.com/ctreminiom/go-atlassian/v2/service" + "github.com/ctreminiom/go-atlassian/v2/service/jira" + "net/http" + "path" +) + +func NewIssueArchivalService(client service.Connector, version string) *IssueArchivalService { + return &IssueArchivalService{ + internalClient: &internalIssueArchivalImpl{c: client, version: version}, + } +} + +type IssueArchivalService struct { + internalClient jira.ArchiveService +} + +func (i *IssueArchivalService) Preserve(ctx context.Context, issueIdsOrKeys []string) (*model.IssueArchivalSyncResponseScheme, *model.ResponseScheme, error) { + return i.internalClient.Preserve(ctx, issueIdsOrKeys) +} + +func (i *IssueArchivalService) PreserveByJQL(ctx context.Context, jql string) (string, *model.ResponseScheme, error) { + return i.internalClient.PreserveByJQL(ctx, jql) +} + +func (i *IssueArchivalService) Restore(ctx context.Context, issueIdsOrKeys []string) (*model.IssueArchivalSyncResponseScheme, *model.ResponseScheme, error) { + return i.internalClient.Restore(ctx, issueIdsOrKeys) +} + +func (i *IssueArchivalService) Export(ctx context.Context, payload *model.IssueArchivalExportPayloadScheme) (string, *model.ResponseScheme, error) { + return i.internalClient.Export(ctx, payload) +} + +type internalIssueArchivalImpl struct { + c service.Connector + version string +} + +func (i *internalIssueArchivalImpl) Preserve(ctx context.Context, issueIdsOrKeys []string) (result *model.IssueArchivalSyncResponseScheme, response *model.ResponseScheme, err error) { + + if len(issueIdsOrKeys) == 0 { + return nil, nil, model.ErrNoIssuesSlice + } + + payload := make(map[string]interface{}) + payload["issueIdsOrKeys"] = issueIdsOrKeys + + endpoint := fmt.Sprintf("rest/api/%s/issue/archive", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload) + if err != nil { + return nil, nil, err + } + + report := new(model.IssueArchivalSyncResponseScheme) + response, err = i.c.Call(request, report) + if err != nil { + return nil, response, err + } + + return report, response, nil +} + +func (i *internalIssueArchivalImpl) PreserveByJQL(ctx context.Context, jql string) (taskID string, response *model.ResponseScheme, err error) { + + if jql == "" { + return "", nil, model.ErrNoJQL + } + + payload := make(map[string]interface{}) + payload["jql"] = jql + + endpoint := fmt.Sprintf("rest/api/%s/issue/archive", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload) + if err != nil { + return "", nil, err + } + + response, err = i.c.Call(request, nil) + if err != nil { + return "", response, err + } + + return path.Base(response.Bytes.String()), response, nil +} + +func (i *internalIssueArchivalImpl) Restore(ctx context.Context, issueIdsOrKeys []string) (result *model.IssueArchivalSyncResponseScheme, response *model.ResponseScheme, err error) { + + if len(issueIdsOrKeys) == 0 { + return nil, nil, model.ErrNoIssuesSlice + } + + payload := make(map[string]interface{}) + payload["issueIdsOrKeys"] = issueIdsOrKeys + + endpoint := fmt.Sprintf("rest/api/%s/issue/unarchive", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload) + if err != nil { + return nil, nil, err + } + + report := new(model.IssueArchivalSyncResponseScheme) + response, err = i.c.Call(request, report) + if err != nil { + return nil, response, err + } + + return report, response, nil +} + +func (i *internalIssueArchivalImpl) Export(ctx context.Context, payload *model.IssueArchivalExportPayloadScheme) (taskID string, response *model.ResponseScheme, err error) { + + endpoint := fmt.Sprintf("rest/api/%s/issues/archive/export", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload) + if err != nil { + return "", nil, err + } + + response, err = i.c.Call(request, nil) + if err != nil { + return "", response, err + } + + return "", response, nil +} diff --git a/jira/v2/api_client_impl.go b/jira/v2/api_client_impl.go index 0b4ed10c..28a688f1 100644 --- a/jira/v2/api_client_impl.go +++ b/jira/v2/api_client_impl.go @@ -397,6 +397,8 @@ func New(httpClient common.HTTPClient, site string) (*Client, error) { client.NotificationScheme = projectNotificationScheme client.Team = internal.NewTeamService(client) + client.Archive = internal.NewIssueArchivalService(client, APIVersion) + return client, nil } @@ -423,6 +425,8 @@ type Client struct { JQL *internal.JQLService NotificationScheme *internal.NotificationSchemeService Team *internal.TeamService + + Archive *internal.IssueArchivalService } // NewRequest creates an API request. diff --git a/jira/v3/api_client_impl.go b/jira/v3/api_client_impl.go index e29db9e4..30cb60e3 100644 --- a/jira/v3/api_client_impl.go +++ b/jira/v3/api_client_impl.go @@ -397,6 +397,8 @@ func New(httpClient common.HTTPClient, site string) (*Client, error) { client.NotificationScheme = projectNotificationScheme client.Team = internal.NewTeamService(client) + client.Archival = internal.NewIssueArchivalService(client, APIVersion) + return client, nil } @@ -423,6 +425,8 @@ type Client struct { JQL *internal.JQLService NotificationScheme *internal.NotificationSchemeService Team *internal.TeamService + + Archival *internal.IssueArchivalService } // NewRequest creates an API request. diff --git a/service/jira/archive.go b/service/jira/archive.go index 6098b0e3..f8cf1ac1 100644 --- a/service/jira/archive.go +++ b/service/jira/archive.go @@ -5,9 +5,75 @@ import ( "github.com/ctreminiom/go-atlassian/v2/pkg/infra/models" ) +// ArchiveService provides methods to manage issue archival operations, including preserving, restoring, and exporting archived issues. type ArchiveService interface { + + // Preserve archives the given issues based on their issue IDs or keys. + // + // Parameters: + // - ctx: The context for controlling request lifecycle and deadlines. + // - issueIdsOrKeys: A list of issue IDs or keys to be archived. + // + // Returns: + // - result: A structure containing details of the archival synchronization process. + // - response: The HTTP response scheme for the request. + // - err: An error if the operation fails. + // + // Example Usage: + // result, response, err := issue.archive.Preserve(ctx, []string{"ISSUE-123", "ISSUE-456"}) + // + // https://docs.go-atlassian.io/jira-software-cloud/application-roles#get-application-role Preserve(ctx context.Context, issueIdsOrKeys []string) (result *models.IssueArchivalSyncResponseScheme, response *models.ResponseScheme, err error) + + // PreserveByJQL archives issues that match the provided JQL query. + // + // Parameters: + // - ctx: The context for request lifecycle management. + // - jql: The JQL query to select issues for archival. + // + // Returns: + // - taskID: A unique identifier for the asynchronous archival task. + // - response: The HTTP response scheme for the request. + // - err: An error if the operation fails. + // + // Example Usage: + // taskID, response, err := issue.Archive.PreserveByJQL(ctx, "project = ABC AND status = 'Resolved'") + // + // https://docs.go-atlassian.io/jira-software-cloud/application-roles#get-application-role PreserveByJQL(ctx context.Context, jql string) (taskID string, response *models.ResponseScheme, err error) + + // Restore brings back the given archived issues using their issue IDs or keys. + // + // Parameters: + // - ctx: The context for controlling request execution. + // - issueIdsOrKeys: A list of issue IDs or keys to be restored from the archive. + // + // Returns: + // - result: A structure containing details of the restoration process. + // - response: The HTTP response scheme for the request. + // - err: An error if the operation fails. + // + // Example Usage: + // result, response, err := issue.Archive.Restore(ctx, []string{"ISSUE-789"}) + // + // https://docs.go-atlassian.io/jira-software-cloud/application-roles#get-application-role Restore(ctx context.Context, issueIdsOrKeys []string) (result *models.IssueArchivalSyncResponseScheme, response *models.ResponseScheme, err error) + + // Export generates an export of archived issues based on the provided payload. + // + // Parameters: + // - ctx: The context for controlling request execution. + // - payload: The export configuration, including filters and format specifications. + // + // Returns: + // - taskID: A unique identifier for the asynchronous export task. + // - response: The HTTP response scheme for the request. + // - err: An error if the operation fails. + // + // Example Usage: + // exportPayload := &models.IssueArchivalExportPayloadScheme{Format: "CSV", Fields: []string{"summary", "status"}} + // taskID, response, err := issue.Archive.Export(ctx, exportPayload) + // + // https://docs.go-atlassian.io/jira-software-cloud/application-roles#get-application-role Export(ctx context.Context, payload *models.IssueArchivalExportPayloadScheme) (taskID string, response *models.ResponseScheme, err error) }