Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add jira_issues datasource #257

Merged
merged 2 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .goreleaser-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,12 @@ builds:
no_unique_dist_dir: true
tags:
- fabricplugin

- id: atlassian
main: ./internal/atlassian/cmd
binary: "plugins/blackstork/atlassian@{{ .Version }}"
ldflags: "-X main.version={{.Version}}"
gcflags: all=-N -l
no_unique_dist_dir: true
tags:
- fabricplugin
27 changes: 27 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,20 @@ builds:
tags:
- fabricplugin

- id: plugin_atlassian
main: ./internal/atlassian/cmd
binary: "atlassian@{{ .Version }}"
flags: "-trimpath"
hooks:
post:
- go run ./tools/pluginmeta --namespace blackstork --version {{.Version}} patch --plugin {{.Path}} --os {{.Os}} --arch {{.Arch}}
goos:
- linux
- windows
- darwin
tags:
- fabricplugin

archives:
- id: fabric
format: tar.gz
Expand Down Expand Up @@ -457,6 +471,7 @@ archives:
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}

- id: plugin_iris
format: tar.gz
builds:
Expand All @@ -469,6 +484,18 @@ archives:
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}

- id: plugin_atlassian
format: tar.gz
builds:
- plugin_atlassian
name_template: >-
plugin_atlassian_
{{- .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}

dockers:
- use: buildx
goos: linux
Expand Down
4 changes: 4 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ packages:
AzureOpenAIClient:
MicrosoftGraphClient:
MicrosoftSecurityClient:
github.com/blackstork-io/fabric/internal/atlassian/client:
config:
interfaces:
Client:
github.com/blackstork-io/fabric/internal/crowdstrike:
config:
interfaces:
Expand Down
34 changes: 34 additions & 0 deletions docs/plugins/atlassian/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
title: blackstork/atlassian
weight: 20
plugin:
name: blackstork/atlassian
description: "The `atlassian` plugin for Atlassian Cloud."
tags: []
version: "v0.4.2"
source_github: "https://github.com/blackstork-io/fabric/tree/main/internal/atlassian/"
type: docs
hideInMenu: true
---

{{< plugin-header "blackstork/atlassian" "atlassian" "v0.4.2" >}}

## Description
The `atlassian` plugin for Atlassian Cloud.

## Installation

To install the plugin, add it to `plugin_versions` map in the Fabric global configuration block (see [Global configuration]({{< ref "configs.md#global-configuration" >}}) for more details), with a version constraint restricting which available versions of the plugin the codebase is compatible with:

```hcl
fabric {
plugin_versions = {
"blackstork/atlassian" = ">= v0.4.2"
}
}
```


## Data sources

{{< plugin-resources "atlassian" "data-source" >}}
114 changes: 114 additions & 0 deletions docs/plugins/atlassian/data-sources/jira_issues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
title: "`jira_issues` data source"
plugin:
name: blackstork/atlassian
description: "Retrieve issues from Jira"
tags: []
version: "v0.4.2"
source_github: "https://github.com/blackstork-io/fabric/tree/main/internal/atlassian/"
resource:
type: data-source
type: docs
---

{{< breadcrumbs 2 >}}

{{< plugin-resource-header "blackstork/atlassian" "atlassian" "v0.4.2" "jira_issues" "data source" >}}

## Description
Retrieve issues from Jira.

## Installation

To use `jira_issues` data source, you must install the plugin `blackstork/atlassian`.

To install the plugin, add the full plugin name to the `plugin_versions` map in the Fabric global configuration block (see [Global configuration]({{< ref "configs.md#global-configuration" >}}) for more details), as shown below:

```hcl
fabric {
plugin_versions = {
"blackstork/atlassian" = ">= v0.4.2"
}
}
```

Note the version constraint set for the plugin.

## Configuration

The data source supports the following configuration arguments:

```hcl
config data jira_issues {
# Account Domain.
#
# Required string.
# Must be non-empty
# For example:
domain = "some string"

# Account Email.
#
# Required string.
# Must be non-empty
# For example:
account_email = "some string"

# API Token.
#
# Required string.
# Must be non-empty
# For example:
api_token = "some string"
}
```

## Usage

The data source supports the following execution arguments:

```hcl
data jira_issues {
# Use expand to include additional information about issues in the response.
#
# Optional string.
# Must be one of: "renderedFields", "names", "schema", "changelog"
# For example:
# expand = "names"
#
# Default value:
expand = null

# A list of fields to return for each issue.
#
# Optional list of string.
# For example:
# fields = ["*all"]
#
# Default value:
fields = null

# A JQL expression. For performance reasons, this field requires a bounded query. A bounded query is a query with a search restriction.
#
# Optional string.
# For example:
# jql = "order by key desc"
#
# Default value:
jql = null

# A list of up to 5 issue properties to include in the results.
#
# Optional list of string.
# Must have a length of at most 5
# Default value:
properties = []

# Size limit to retrieve.
#
# Optional number.
# Must be >= 0
# Default value:
size = 0
}
```
23 changes: 23 additions & 0 deletions docs/plugins/plugins.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
[
{
"name": "blackstork/atlassian",
"version": "v0.4.2",
"shortname": "atlassian",
"resources": [
{
"name": "jira_issues",
"type": "data-source",
"config_params": [
"account_email",
"api_token",
"domain"
],
"arguments": [
"expand",
"fields",
"jql",
"properties",
"size"
]
}
]
},
{
"name": "blackstork/builtin",
"version": "v0.4.2",
Expand Down
28 changes: 28 additions & 0 deletions examples/templates/atlassian/example.fabric
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
fabric {
plugin_versions = {
"blackstork/atlassian" = ">= 0.5 < 1.0 || 0.5.0-rev0"
}
}

config data jira_issues {
domain = env.JIRA_DOMAIN
account_email = env.JIRA_ACCOUNT_EMAIL
api_token = env.JIRA_API_TOKEN
}

document "example" {
title = "Using atlassian plugin"
data jira_issues "my_issues" {
expand = "names"
fields = ["*all"]
jql = "project = TEST"
size = 5
}
content title {
value = "My Jira Issues"
}
content list {
item_template = "{{.key}}: {{.fields.summary}}"
items = query_jq(".data.jira_issues.my_issues")
}
}
98 changes: 98 additions & 0 deletions internal/atlassian/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package client

import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/url"
"time"
)

type Client interface {
SearchIssues(ctx context.Context, req *SearchIssuesReq) (*SearchIssuesRes, error)
}

type client struct {
apiURL string
apiToken string
accountEmail string
}

func (c *client) auth(r *http.Request) {
r.SetBasicAuth(c.accountEmail, c.apiToken)
}

func (c *client) makeHTTPClient() *http.Client {
httpClient := &http.Client{
Timeout: 15 * time.Second,
}

return httpClient
}

func (c *client) makeURL(path ...string) (*url.URL, error) {
addr, err := url.JoinPath(c.apiURL, path...)
if err != nil {
return nil, err
}
return url.Parse(addr)
}

func New(apiURL, accountEmail, apiToken string) Client {
return &client{
apiURL: apiURL,
accountEmail: accountEmail,
apiToken: apiToken,
}
}

func (c *client) handleError(res *http.Response) error {
var clientErr Error

if err := json.NewDecoder(res.Body).Decode(&clientErr); err != nil {
return err
}

return &clientErr
}

func (c *client) SearchIssues(ctx context.Context, req *SearchIssuesReq) (*SearchIssuesRes, error) {
u, err := c.makeURL("/rest/api/3/search/jql")
if err != nil {
return nil, err
}

body, err := json.Marshal(req)
if err != nil {
return nil, err
}

r, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), bytes.NewReader(body))
if err != nil {
return nil, err
}

r.Header.Set("Content-Type", "application/json")
r.Header.Set("Accept", "application/json")
c.auth(r)

client := c.makeHTTPClient()
res, err := client.Do(r)
if err != nil {
return nil, err
}

defer res.Body.Close()

if res.StatusCode != http.StatusOK {
return nil, c.handleError(res)
}

var data SearchIssuesRes
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
return nil, err
}

return &data, nil
}
Loading