Skip to content

Commit

Permalink
Merge pull request #20 from CruGlobal/add-project-view-resource
Browse files Browse the repository at this point in the history
feat(project_view): Add project view resource and data source
  • Loading branch information
Omicron7 authored Jan 27, 2025
2 parents 40fb0e5 + a1a3dd5 commit 8c3919c
Show file tree
Hide file tree
Showing 22 changed files with 789 additions and 13 deletions.
1 change: 1 addition & 0 deletions docs/data-sources/project_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ data "semaphoreui_project_template" "build" {
- `suppress_success_alerts` (Boolean) Suppress success alerts.
- `survey_vars` (Attributes List) Survey variables. (see [below for nested schema](#nestedatt--survey_vars))
- `vaults` (Attributes List) Ansible Vault Passwords. (see [below for nested schema](#nestedatt--vaults))
- `view_id` (Number) The view ID that the templates belongs to.

<a id="nestedatt--build"></a>
### Nested Schema for `build`
Expand Down
29 changes: 29 additions & 0 deletions docs/data-sources/project_view.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "semaphoreui_project_view Data Source - semaphoreui"
subcategory: ""
description: |-
The project view data source allows you to read a Views details.
---

# semaphoreui_project_view (Data Source)

The project view data source allows you to read a Views details.



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `project_id` (Number) The project ID that the template belongs to.

### Optional

- `id` (Number) The view ID. Ensure that one and only one attribute from this collection is set : `id`, `title`.
- `title` (String) Title of the view. Ensure that one and only one attribute from this collection is set : `id`, `title`.

### Read-Only

- `position` (Number) The position of the view in the project.
1 change: 1 addition & 0 deletions docs/resources/project_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ resource "semaphoreui_project_template" "deploy" {
- `suppress_success_alerts` (Boolean) Suppress success alerts. Value defaults to `false`.
- `survey_vars` (Attributes List) Survey variables. (see [below for nested schema](#nestedatt--survey_vars))
- `vaults` (Attributes List) Ansible Vault Passwords. (see [below for nested schema](#nestedatt--vaults))
- `view_id` (Number) The view ID that the templates belongs to.

### Read-Only

Expand Down
56 changes: 56 additions & 0 deletions docs/resources/project_view.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "semaphoreui_project_view Resource - semaphoreui"
subcategory: ""
description: |-
The project view resource allows you to manage a Views in a project.
---

# semaphoreui_project_view (Resource)

The project view resource allows you to manage a Views in a project.

## Example Usage

```terraform
resource "semaphoreui_project" "project" {
name = "Example Project"
}
resource "semaphoreui_project_view" "view" {
project_id = semaphoreui_project.project.id
title = "Section A"
position = 0
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `position` (Number) The position of the view in the project. Value must be at least 0.
- `project_id` (Number) (ForceNew) The project ID that the template belongs to.
- `title` (String) Title of the view.

### Read-Only

- `id` (Number) The view ID.

## Import

Import is supported using the following syntax:

```shell
# Import ID is specified by the string "project/{project_id}/view/{view_id}".
# - {project_id} is the ID of the project in SemaphoreUI.
# - {view_id} is the ID of the view in SemaphoreUI.
terraform import semaphoreui_project_view.example project/1/view/2
```
Or using `import {}` block in the configuration file:
```hcl
import {
to = semaphoreui_project_view.example
id = "project/1/view/2"
}
```
11 changes: 11 additions & 0 deletions examples/data-sources/semaphoreui_view_repository/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Lookup by View ID
data "semaphoreui_project_view" "view" {
project_id = 1
id = 3
}

# Lookup by View Name
data "semaphoreui_project_view" "prod" {
project_id = 1
title = "Prod"
}
11 changes: 11 additions & 0 deletions examples/resources/semaphoreui_project_view/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Import ID is specified by the string "project/{project_id}/view/{view_id}".
# - {project_id} is the ID of the project in SemaphoreUI.
# - {view_id} is the ID of the view in SemaphoreUI.
terraform import semaphoreui_project_view.example project/1/view/2
```
Or using `import {}` block in the configuration file:
```hcl
import {
to = semaphoreui_project_view.example
id = "project/1/view/2"
}
9 changes: 9 additions & 0 deletions examples/resources/semaphoreui_project_view/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
resource "semaphoreui_project" "project" {
name = "Example Project"
}

resource "semaphoreui_project_view" "view" {
project_id = semaphoreui_project.project.id
title = "Section A"
position = 0
}
9 changes: 9 additions & 0 deletions internal/provider/project_template_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ resource "semaphoreui_project_environment" "test" {
}]
}
resource "semaphoreui_project_view" "test" {
project_id = semaphoreui_project.test.id
title = "Title"
position = 2
}
# Task Template
resource "semaphoreui_project_template" "test" {
project_id = semaphoreui_project.test.id
Expand All @@ -59,6 +65,7 @@ resource "semaphoreui_project_template" "test" {
"--help",
"--vvv",
]
view_id = semaphoreui_project_view.test.id
allow_override_args_in_task = true
survey_vars = [{
Expand Down Expand Up @@ -178,6 +185,7 @@ func TestAcc_ProjectTemplateDataSource_basicID(t *testing.T) {
resource.TestCheckResourceAttrSet("data.semaphoreui_project_template.test", "environment_id"),
resource.TestCheckResourceAttrSet("data.semaphoreui_project_template.test", "repository_id"),
resource.TestCheckResourceAttrSet("data.semaphoreui_project_template.test", "inventory_id"),
resource.TestCheckResourceAttrSet("data.semaphoreui_project_template.test", "view_id"),
),
},
},
Expand Down Expand Up @@ -207,6 +215,7 @@ func TestAcc_ProjectTemplateDataSource_basicName(t *testing.T) {
resource.TestCheckResourceAttrSet("data.semaphoreui_project_template.test", "environment_id"),
resource.TestCheckResourceAttrSet("data.semaphoreui_project_template.test", "repository_id"),
resource.TestCheckResourceAttrSet("data.semaphoreui_project_template.test", "inventory_id"),
resource.TestCheckNoResourceAttr("data.semaphoreui_project_template.test", "view_id"),
),
},
},
Expand Down
9 changes: 9 additions & 0 deletions internal/provider/project_template_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ func convertProjectTemplateModelToTemplateRequest(ctx context.Context, template
if !template.GitBranch.IsNull() && !template.GitBranch.IsUnknown() {
model.GitBranch = template.GitBranch.ValueString()
}
if !template.ViewID.IsNull() && !template.ViewID.IsUnknown() {
model.ViewID = template.ViewID.ValueInt64Pointer()
}

if len(template.Arguments.Elements()) != 0 {
var arguments []string
Expand Down Expand Up @@ -182,6 +185,12 @@ func convertTemplateResponseToProjectTemplateModel(ctx context.Context, request
model.GitBranch = prev.GitBranch
}

if request.ViewID != nil {
model.ViewID = types.Int64PointerValue(request.ViewID)
} else {
model.ViewID = prev.ViewID
}

var arguments []string
if json.Unmarshal([]byte(request.Arguments), &arguments) != nil {
model.Arguments = types.ListNull(types.StringType)
Expand Down
10 changes: 9 additions & 1 deletion internal/provider/project_template_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@ resource "semaphoreui_project_environment" "test" {
project_id = semaphoreui_project.test.id
name = "Env-%[1]s"
}
`, nameSuffix)
resource "semaphoreui_project_view" "test" {
project_id = semaphoreui_project.test.id
title = "Test View"
position = 0
}`, nameSuffix)
}

func testAccProjectTemplateConfig(nameSuffix string, extras string) string {
Expand Down Expand Up @@ -181,6 +186,7 @@ func TestAcc_ProjectTemplateResource_basic(t *testing.T) {
resource.TestCheckNoResourceAttr("semaphoreui_project_template.test", "vaults"),
resource.TestCheckNoResourceAttr("semaphoreui_project_template.test", "build"),
resource.TestCheckNoResourceAttr("semaphoreui_project_template.test", "deploy"),
resource.TestCheckNoResourceAttr("semaphoreui_project_template.test", "view_id"),

resource.TestCheckResourceAttrSet("semaphoreui_project_template.test", "id"),
resource.TestCheckResourceAttrSet("semaphoreui_project_template.test", "project_id"),
Expand All @@ -205,6 +211,7 @@ arguments = [
"--help",
"--verbose",
]
view_id = semaphoreui_project_view.test.id
`),
Check: resource.ComposeAggregateTestCheckFunc(
testAccProjectTemplateExists("semaphoreui_project_template.test", ""),
Expand All @@ -229,6 +236,7 @@ arguments = [
resource.TestCheckResourceAttrSet("semaphoreui_project_template.test", "inventory_id"),
resource.TestCheckResourceAttrSet("semaphoreui_project_template.test", "environment_id"),
resource.TestCheckResourceAttrSet("semaphoreui_project_template.test", "repository_id"),
resource.TestCheckResourceAttrSet("semaphoreui_project_template.test", "view_id"),
),
},
// Delete testing
Expand Down
13 changes: 12 additions & 1 deletion internal/provider/project_template_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type (
EnvironmentID types.Int64 `tfsdk:"environment_id"`
InventoryID types.Int64 `tfsdk:"inventory_id"`
RepositoryID types.Int64 `tfsdk:"repository_id"`
//ViewID types.Int64 `tfsdk:"view_id"`
ViewID types.Int64 `tfsdk:"view_id"`

Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
Expand Down Expand Up @@ -280,6 +280,17 @@ func ProjectTemplateSchema() superschema.Schema {
Computed: true,
},
},
"view_id": superschema.Int64Attribute{
Common: &schemaR.Int64Attribute{
MarkdownDescription: "The view ID that the templates belongs to.",
},
Resource: &schemaR.Int64Attribute{
Optional: true,
},
DataSource: &schemaD.Int64Attribute{
Computed: true,
},
},
"arguments": superschema.ListAttribute{
Common: &schemaR.ListAttribute{
MarkdownDescription: "Commandline arguments passed to the application.",
Expand Down
105 changes: 105 additions & 0 deletions internal/provider/project_view_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package provider

import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/types"
apiclient "terraform-provider-semaphoreui/semaphoreui/client"
"terraform-provider-semaphoreui/semaphoreui/client/project"
)

// Ensure the implementation satisfies the expected interfaces.
var (
_ datasource.DataSource = &projectViewDataSource{}
)

func NewProjectViewDataSource() datasource.DataSource {
return &projectViewDataSource{}
}

type projectViewDataSource struct {
client *apiclient.SemaphoreUI
}

func (d *projectViewDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*apiclient.SemaphoreUI)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
"Expected *client.SemaphoreUI, got %T. Please report this issue to the provider developers.",
)
return
}
d.client = client
}

// Metadata returns the data source type name.
func (d *projectViewDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_project_view"
}

// Schema defines the schema for the data source.
func (d *projectViewDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = ProjectViewSchema().GetDataSource(ctx)
}

func (d *projectViewDataSource) GetViewModelByTitle(projectID int64, title types.String) (*ProjectViewModel, error) {
payload, err := d.client.Project.GetProjectProjectIDViews(&project.GetProjectProjectIDViewsParams{
ProjectID: projectID,
}, nil)
if err != nil {
return nil, fmt.Errorf("could not read Views: %s", err.Error())
}

for _, view := range payload.Payload {
if view.Title == title.ValueString() {
viewModel := convertViewResponseToProjectViewModel(view)
return &viewModel, nil
}
}
return nil, fmt.Errorf("view with title %s not found", title.ValueString())
}

func (d *projectViewDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var config ProjectViewModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}

var model ProjectViewModel
if !config.ID.IsNull() && !config.ID.IsUnknown() {
response, err := d.client.Project.GetProjectProjectIDViewsViewID(&project.GetProjectProjectIDViewsViewIDParams{
ProjectID: config.ProjectID.ValueInt64(),
ViewID: config.ID.ValueInt64(),
}, nil)
if err != nil {
resp.Diagnostics.AddError(
"Error Reading SemaphoreUI Project View",
"Could not read project view, unexpected error: "+err.Error(),
)
return
}
model = convertViewResponseToProjectViewModel(response.Payload)
} else if !config.Title.IsNull() && !config.Title.IsUnknown() {
view, err := d.GetViewModelByTitle(config.ProjectID.ValueInt64(), config.Title)
if err != nil {
resp.Diagnostics.AddError(
"Error Reading SemaphoreUI Project View",
err.Error(),
)
return
}
model = *view
}

resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
}
}
Loading

0 comments on commit 8c3919c

Please sign in to comment.