Skip to content

Commit 42540ef

Browse files
authored
Add plural data source for retrieving NPM Packages from an Artifact Registry repository (#14805)
1 parent 5916642 commit 42540ef

File tree

4 files changed

+273
-0
lines changed

4 files changed

+273
-0
lines changed

mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
3131
"google_artifact_registry_locations": artifactregistry.DataSourceGoogleArtifactRegistryLocations(),
3232
"google_artifact_registry_maven_artifact": artifactregistry.DataSourceArtifactRegistryMavenArtifact(),
3333
"google_artifact_registry_npm_package": artifactregistry.DataSourceArtifactRegistryNpmPackage(),
34+
"google_artifact_registry_npm_packages": artifactregistry.DataSourceArtifactRegistryNpmPackages(),
3435
"google_artifact_registry_package": artifactregistry.DataSourceArtifactRegistryPackage(),
3536
"google_artifact_registry_python_package": artifactregistry.DataSourceArtifactRegistryPythonPackage(),
3637
"google_artifact_registry_repositories": artifactregistry.DataSourceArtifactRegistryRepositories(),
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package artifactregistry
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"net/url"
7+
"strings"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
11+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
12+
)
13+
14+
func DataSourceArtifactRegistryNpmPackages() *schema.Resource {
15+
return &schema.Resource{
16+
Read: dataSourceArtifactRegistryNpmPackagesRead,
17+
Schema: map[string]*schema.Schema{
18+
"location": {
19+
Type: schema.TypeString,
20+
Required: true,
21+
},
22+
"repository_id": {
23+
Type: schema.TypeString,
24+
Required: true,
25+
},
26+
"project": {
27+
Type: schema.TypeString,
28+
Optional: true,
29+
},
30+
"npm_packages": {
31+
Type: schema.TypeList,
32+
Computed: true,
33+
Elem: &schema.Resource{
34+
Schema: map[string]*schema.Schema{
35+
"package_name": {
36+
Type: schema.TypeString,
37+
Required: true,
38+
Description: "The name of the Npm package.",
39+
},
40+
"version": {
41+
Type: schema.TypeString,
42+
Computed: true,
43+
Description: "The version of the Npm package.",
44+
},
45+
"tags": {
46+
Type: schema.TypeList,
47+
Computed: true,
48+
Description: "The tags associated with the Npm package.",
49+
Elem: &schema.Schema{Type: schema.TypeString},
50+
},
51+
"name": {
52+
Type: schema.TypeString,
53+
Computed: true,
54+
Description: "The fully qualified name of the Npm package.",
55+
},
56+
"create_time": {
57+
Type: schema.TypeString,
58+
Computed: true,
59+
Description: "The time the package was created.",
60+
},
61+
"update_time": {
62+
Type: schema.TypeString,
63+
Computed: true,
64+
Description: "The time the package was last updated.",
65+
},
66+
},
67+
},
68+
},
69+
},
70+
}
71+
}
72+
73+
func dataSourceArtifactRegistryNpmPackagesRead(d *schema.ResourceData, meta interface{}) error {
74+
config := meta.(*transport_tpg.Config)
75+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
76+
if err != nil {
77+
return err
78+
}
79+
80+
project, err := tpgresource.GetProject(d, config)
81+
if err != nil {
82+
return err
83+
}
84+
85+
basePath, err := tpgresource.ReplaceVars(d, config, "{{ArtifactRegistryBasePath}}")
86+
if err != nil {
87+
return fmt.Errorf("Error setting Artifact Registry base path: %s", err)
88+
}
89+
90+
resourcePath, err := tpgresource.ReplaceVars(d, config, fmt.Sprintf("projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}/npmPackages"))
91+
if err != nil {
92+
return fmt.Errorf("Error setting resource path: %s", err)
93+
}
94+
95+
urlRequest := basePath + resourcePath
96+
97+
headers := make(http.Header)
98+
npmPackages := make([]map[string]interface{}, 0)
99+
pageToken := ""
100+
101+
for {
102+
u, err := url.Parse(urlRequest)
103+
if err != nil {
104+
return fmt.Errorf("Error parsing URL: %s", err)
105+
}
106+
107+
q := u.Query()
108+
if pageToken != "" {
109+
q.Set("pageToken", pageToken)
110+
}
111+
u.RawQuery = q.Encode()
112+
113+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
114+
Config: config,
115+
Method: "GET",
116+
RawURL: u.String(),
117+
UserAgent: userAgent,
118+
Headers: headers,
119+
})
120+
121+
if err != nil {
122+
return fmt.Errorf("Error listing Artifact Registry Npm packages: %s", err)
123+
}
124+
125+
if items, ok := res["npmPackages"].([]interface{}); ok {
126+
for _, item := range items {
127+
pkg := item.(map[string]interface{})
128+
129+
name, ok := pkg["name"].(string)
130+
if !ok {
131+
return fmt.Errorf("Error getting Artifact Registry Npm package name: %s", err)
132+
}
133+
134+
lastComponent := name[strings.LastIndex(name, "/")+1:]
135+
packageName := strings.SplitN(lastComponent, ":", 2)[0]
136+
137+
var tags []string
138+
if rawTags, ok := pkg["tags"].([]interface{}); ok {
139+
for _, tag := range rawTags {
140+
if tagStr, ok := tag.(string); ok {
141+
tags = append(tags, tagStr)
142+
}
143+
}
144+
}
145+
146+
getString := func(m map[string]interface{}, key string) string {
147+
if v, ok := m[key].(string); ok {
148+
return v
149+
}
150+
return ""
151+
}
152+
153+
npmPackages = append(npmPackages, map[string]interface{}{
154+
"package_name": packageName,
155+
"name": name,
156+
"version": getString(pkg, "version"),
157+
"tags": tags,
158+
"create_time": getString(pkg, "createTime"),
159+
"update_time": getString(pkg, "updateTime"),
160+
})
161+
}
162+
}
163+
164+
if nextToken, ok := res["nextPageToken"].(string); ok && nextToken != "" {
165+
pageToken = nextToken
166+
} else {
167+
break
168+
}
169+
}
170+
171+
if err := d.Set("project", project); err != nil {
172+
return fmt.Errorf("Error setting project: %s", err)
173+
}
174+
175+
if err := d.Set("npm_packages", npmPackages); err != nil {
176+
return fmt.Errorf("Error setting Artifact Registry Npm packages: %s", err)
177+
}
178+
179+
d.SetId(resourcePath)
180+
181+
return nil
182+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package artifactregistry_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
7+
"github.com/hashicorp/terraform-provider-google/google/acctest"
8+
)
9+
10+
func TestAccDataSourceArtifactRegistryNpmPackages_basic(t *testing.T) {
11+
t.Parallel()
12+
13+
// At the moment there are no public NPM packages available in Artifact Registry.
14+
// This test is skipped to avoid unnecessary failures.
15+
// As soon as there are public packages available, this test can be enabled by removing the skip and adjusting the configuration accordingly.
16+
t.Skip("No public NPM packages available in Artifact Registry")
17+
18+
acctest.VcrTest(t, resource.TestCase{
19+
PreCheck: func() { acctest.AccTestPreCheck(t) },
20+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
21+
Steps: []resource.TestStep{
22+
{
23+
Config: testAccDataSourceArtifactRegistryNpmPackagesConfig,
24+
Check: resource.ComposeTestCheckFunc(
25+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_npm_packages.test", "project"),
26+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_npm_packages.test", "location"),
27+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_npm_packages.test", "repository_id"),
28+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_npm_packages.test", "npm_packages.0.package_name"),
29+
resource.TestCheckResourceAttrSet("data.google_artifact_registry_npm_packages.test", "npm_packages.0.name"),
30+
),
31+
},
32+
},
33+
})
34+
}
35+
36+
const testAccDataSourceArtifactRegistryNpmPackagesConfig = `
37+
data "google_artifact_registry_npm_packages" "test" {
38+
project = "example-project"
39+
location = "us"
40+
repository_id = "example-repo"
41+
}
42+
`
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
subcategory: "Artifact Registry"
3+
description: |-
4+
Get information about Npm packages within a Google Artifact Registry repository.
5+
---
6+
7+
# google_artifact_registry_npm_packages
8+
9+
Get information about Artifact Registry Npm packages.
10+
See [the official documentation](https://cloud.google.com/artifact-registry/docs/nodejs)
11+
and [API](https://cloud.google.com/artifact-registry/docs/reference/rest/v1/projects.locations.repositories.npmPackages/list).
12+
13+
## Example Usage
14+
15+
```hcl
16+
data "google_artifact_registry_npm_packages" "my_packages" {
17+
location = "us-central1"
18+
repository_id = "example-repo"
19+
}
20+
```
21+
22+
## Argument Reference
23+
24+
The following arguments are supported:
25+
26+
* `location` - (Required) The location of the Artifact Registry repository.
27+
28+
* `repository_id` - (Required) The last part of the repository name to fetch from.
29+
30+
* `project` - (Optional) The project ID in which the resource belongs. If it is not provided, the provider project is used.
31+
32+
## Attributes Reference
33+
34+
The following attributes are exported:
35+
36+
* `npm_packages` - A list of all retrieved Artifact Registry Npm packages. Structure is [defined below](#nested_npm_packages).
37+
38+
<a name="nested_npm_packages"></a>The `npm_packages` block supports:
39+
40+
* `name` - The fully qualified name of the fetched package. This name has the form: `projects/{{project}}/locations/{{location}}/repository/{{repository_id}}/npmPackages/{{npmPackage}}`. For example, `projects/example-project/locations/us-central1/repository/example-repo/npmPackages/my-test-package:0.0.1`
41+
42+
* `package_name` - Extracted short name of the package (last part of `name`, without version). For example, from `.../my-test-package:0.0.1``my-test-package`.
43+
44+
* `version` - Version of this package.
45+
46+
* `create_time` - The time, as a RFC 3339 string, this package was created.
47+
48+
* `update_time` - The time, as a RFC 3339 string, this package was updated.

0 commit comments

Comments
 (0)