Skip to content

Commit 3364867

Browse files
authored
Fix test compilation, document user_delegate, cover concurrent-update retry (#26)
* Fix non-constant format string vet errors in tests go vet (run by go test on Go 1.24) rejected fmt.Errorf/t.Fatalf calls passing a dynamic string as the format. The test package failed to compile; this blocked running any tests in it. * Add docs and example for googleworkspace_user_delegate The resource shipped in v0.8 but docs were last regenerated before it was added, leaving it the only undocumented resource. Adds the missing example and regenerates the page via tfplugindocs. * Add unit tests for isConcurrentUpdateError retry predicate The 412 and 400 'Invalid Input: resource_id' retry paths added for eventual-consistency handling had no coverage. Tests assert both retryable cases plus negative cases so the predicate can't silently widen. * Correct README to reflect the community fork, not upstream HashiCorp The README was the upstream template verbatim: it claimed HashiCorp maintainership, carried HashiCorp's experimental-status legal disclaimer, and release/issue/registry/contribution links pointing at the archived upstream. Repoints them at this fork, states the actual maintainer, notes the upstream archival, corrects the Go floor (>= 1.24), and points the Unit tests badge at the new workflow. HashiCorp's MPL copyright and Special Recognition are kept. * Fix stale TestConsistencyCheckReachedConsistency expectations Commit 86270a6 lowered numConsistent from 4 to 2 but did not update this test, which still asserted against currConsistent=4 and failed deterministically. Reference numConsistent directly so the test tracks the constant. * Add Unit tests GitHub Actions workflow The README advertised a Unit tests badge but no such workflow existed, and the test package was never run in CI. Runs build, vet, and 'make test' on pushes to main and on PRs. Pins actions to current SHAs (checkout v6.0.3, setup-go v6.4.0). * Bump checkout and setup-go action pins in release workflow release.yml pinned actions/checkout v3.5.3 and actions/setup-go v4.1.0; bump to current v6.0.3 / v6.4.0 to match the new test workflow.
1 parent cec8eac commit 3364867

18 files changed

Lines changed: 238 additions & 47 deletions

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ jobs:
1717
goreleaser:
1818
runs-on: ubuntu-latest
1919
steps:
20-
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
20+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
2121
with:
2222
# Allow goreleaser to access older tag information.
2323
fetch-depth: 0
24-
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
24+
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
2525
with:
2626
go-version-file: 'go.mod'
2727
cache: true

.github/workflows/test.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Unit test workflow.
2+
name: Unit tests
3+
4+
# Run unit tests and vet on pushes to main and on every pull request.
5+
on:
6+
push:
7+
branches:
8+
- main
9+
pull_request:
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
test:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
19+
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
20+
with:
21+
go-version-file: 'go.mod'
22+
cache: true
23+
- name: Build
24+
run: go build ./...
25+
- name: Vet
26+
run: go vet ./...
27+
- name: Unit tests
28+
run: make test

README.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
# Terraform Provider Google Workspace
22
<a href="https://terraform.io">
3-
<img src="https://cdn.rawgit.com/hashicorp/terraform-website/master/content/source/assets/images/logo-hashicorp.svg" alt="Terraform logo" align="right" height="50" />
3+
<img src="https://www.datocms-assets.com/2885/1620155116-brandhcterraformverticalcolor.svg" alt="Terraform logo" align="right" height="50" />
44
</a>
55

6-
![Status: Tech Preview](https://img.shields.io/badge/status-experimental-EAAA32) [![Releases](https://img.shields.io/github/release/hashicorp/terraform-provider-googleworkspace.svg)](https://github.com/hashicorp/terraform-provider-googleworkspace/releases)
7-
[![LICENSE](https://img.shields.io/github/license/hashicorp/terraform-provider-googleworkspace.svg)](https://github.com/hashicorp/terraform-provider-googleworkspace/blob/main/LICENSE)![Unit tests](https://github.com/hashicorp/terraform-provider-googleworkspace/workflows/Unit%20tests/badge.svg)
6+
[![Releases](https://img.shields.io/github/release/SamuZad/terraform-provider-googleworkspace.svg)](https://github.com/SamuZad/terraform-provider-googleworkspace/releases)
7+
[![LICENSE](https://img.shields.io/github/license/SamuZad/terraform-provider-googleworkspace.svg)](https://github.com/SamuZad/terraform-provider-googleworkspace/blob/main/LICENSE)
8+
[![Unit tests](https://github.com/SamuZad/terraform-provider-googleworkspace/actions/workflows/test.yml/badge.svg)](https://github.com/SamuZad/terraform-provider-googleworkspace/actions/workflows/test.yml)
89

910
This Google Workspace provider for Terraform allows you to manage domains, users, and groups in your Google Workspace.
1011

11-
This provider is a technical preview, which means it's a community supported project. It still requires extensive testing and polishing to mature into a HashiCorp officially supported project. Please [file issues](https://github.com/hashicorp/terraform-provider-googleworkspace/issues/new/choose) generously and detail your experience while using the provider. We welcome your feedback.
12-
13-
## Experimental Status
14-
15-
By using the software in this repository (the "Software"), you acknowledge that: (1) the Software is still in development, may change, and has not been released as a commercial product by HashiCorp and is not currently supported in any way by HashiCorp; (2) the Software is provided on an "as-is" basis, and may include bugs, errors, or other issues; (3) the Software is NOT INTENDED FOR PRODUCTION USE, use of the Software may result in unexpected results, loss of data, or other unexpected results, and HashiCorp disclaims any and all liability resulting from use of the Software; and (4) HashiCorp reserves all rights to make all decisions about the features, functionality and commercial release (or non-release) of the Software, at any time and without any obligation or liability whatsoever.
12+
This is a community-maintained fork of the [`hashicorp/terraform-provider-googleworkspace`](https://github.com/hashicorp/terraform-provider-googleworkspace) provider, which was archived by HashiCorp on 2025-06-30. It is published to the Terraform Registry as [`SamuZad/googleworkspace`](https://registry.terraform.io/providers/SamuZad/googleworkspace/latest). Please [file issues](https://github.com/SamuZad/terraform-provider-googleworkspace/issues/new/choose) generously and detail your experience while using the provider. We welcome your feedback.
1613

1714
## Maintainers
1815

19-
This provider plugin is maintained by the Terraform team at [HashiCorp](https://www.hashicorp.com/)
16+
This fork is maintained by [@SamuZad](https://github.com/SamuZad). It descends from the original `hashicorp/terraform-provider-googleworkspace`, which is no longer maintained upstream.
2017

2118
## Requirements
2219

23-
- [Terraform](https://www.terraform.io/downloads.html) >= 0.13.x
24-
- [Go](https://golang.org/doc/install) >= 1.16
20+
- [Terraform](https://www.terraform.io/downloads.html) >= 0.13.x (or [OpenTofu](https://opentofu.org))
21+
- [Go](https://golang.org/doc/install) >= 1.24 (to build the provider)
2522

2623
## Upgrading the provider
2724

@@ -59,7 +56,7 @@ Then commit the changes to `go.mod` and `go.sum`.
5956

6057
## Using The provider
6158

62-
See the [Google Workspace Provider documentation](https://registry.terraform.io/providers/hashicorp/googleworkspace/latest/docs) to get started using the
59+
See the [Google Workspace Provider documentation](https://registry.terraform.io/providers/SamuZad/googleworkspace/latest/docs) to get started using the
6360
Google Workspace provider.
6461

6562
## Developing the Provider
@@ -78,7 +75,7 @@ In order to run the full suite of Acceptance tests, run `make testacc`.
7875
$ make testacc
7976
```
8077

81-
For guidance on common development practices such as testing changes, see the [contribution guidelines](https://github.com/hashicorp/terraform-provider-googleworkspace/blob/main/.github/CONTRIBUTING.md).
78+
For guidance on common development practices such as testing changes, see the [contribution guidelines](https://github.com/SamuZad/terraform-provider-googleworkspace/blob/main/.github/CONTRIBUTING.md).
8279
If you have other development questions we don't cover, please file an issue!
8380

8481
## Special Recognition

docs/resources/user_delegate.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "googleworkspace_user_delegate Resource - terraform-provider-googleworkspace"
4+
subcategory: ""
5+
description: |-
6+
User Delegate resource manages delagation of access to a Gmail user mailbox. User Delegate resides under the https://www.googleapis.com/auth/gmail.settings.sharing client scope.
7+
---
8+
9+
# googleworkspace_user_delegate (Resource)
10+
11+
User Delegate resource manages delagation of access to a Gmail user mailbox. User Delegate resides under the `https://www.googleapis.com/auth/gmail.settings.sharing` client scope.
12+
13+
## Example Usage
14+
15+
```terraform
16+
# Copyright (c) HashiCorp, Inc.
17+
# SPDX-License-Identifier: MPL-2.0
18+
resource "googleworkspace_user" "manager" {
19+
primary_email = "manager@example.com"
20+
password = "34819d7beeabb9260a5c854bc85b3e44"
21+
hash_function = "MD5"
22+
23+
name {
24+
family_name = "Scott"
25+
given_name = "Michael"
26+
}
27+
}
28+
29+
resource "googleworkspace_user" "assistant" {
30+
primary_email = "assistant@example.com"
31+
password = "34819d7beeabb9260a5c854bc85b3e44"
32+
hash_function = "MD5"
33+
34+
name {
35+
family_name = "Martin"
36+
given_name = "Pam"
37+
}
38+
}
39+
40+
# Grant the assistant delegated access to the manager's Gmail mailbox.
41+
resource "googleworkspace_user_delegate" "assistant_to_manager" {
42+
user_id = googleworkspace_user.manager.primary_email
43+
delegate_email = googleworkspace_user.assistant.primary_email
44+
}
45+
```
46+
47+
<!-- schema generated by tfplugindocs -->
48+
## Schema
49+
50+
### Required
51+
52+
- `delegate_email` (String) The email address of the delegate.
53+
- `user_id` (String) The user's email address.
54+
55+
### Optional
56+
57+
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
58+
59+
### Read-Only
60+
61+
- `delegate_verification_status` (String) Indicates whether this address has been verified and can act as a delegate for the account. Read-only.
62+
- `id` (String) The ID of this resource.
63+
64+
<a id="nestedblock--timeouts"></a>
65+
### Nested Schema for `timeouts`
66+
67+
Optional:
68+
69+
- `create` (String)
70+
- `update` (String)
71+
72+
## Import
73+
74+
Import is supported using the following syntax:
75+
76+
```shell
77+
# Copyright (c) HashiCorp, Inc.
78+
# SPDX-License-Identifier: MPL-2.0
79+
terraform import googleworkspace_user_delegate.assistant_to_manager manager@example.com:assistant@example.com
80+
```
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Copyright (c) HashiCorp, Inc.
2+
# SPDX-License-Identifier: MPL-2.0
3+
terraform import googleworkspace_user_delegate.assistant_to_manager manager@example.com:assistant@example.com
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright (c) HashiCorp, Inc.
2+
# SPDX-License-Identifier: MPL-2.0
3+
resource "googleworkspace_user" "manager" {
4+
primary_email = "manager@example.com"
5+
password = "34819d7beeabb9260a5c854bc85b3e44"
6+
hash_function = "MD5"
7+
8+
name {
9+
family_name = "Scott"
10+
given_name = "Michael"
11+
}
12+
}
13+
14+
resource "googleworkspace_user" "assistant" {
15+
primary_email = "assistant@example.com"
16+
password = "34819d7beeabb9260a5c854bc85b3e44"
17+
hash_function = "MD5"
18+
19+
name {
20+
family_name = "Martin"
21+
given_name = "Pam"
22+
}
23+
}
24+
25+
# Grant the assistant delegated access to the manager's Gmail mailbox.
26+
resource "googleworkspace_user_delegate" "assistant_to_manager" {
27+
user_id = googleworkspace_user.manager.primary_email
28+
delegate_email = googleworkspace_user.assistant.primary_email
29+
}

internal/provider/eventual_consistency_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,18 @@ func TestConsistencyCheckReachedConsistency(t *testing.T) {
3434
t.Errorf("Failed: did not reach consistency (numInserts: %d, currConsistent: %d, etagChanges: %d, timeout: %d)", numInserts, cc.currConsistent, cc.etagChanges, int(cc.timeout.Minutes()))
3535
}
3636

37-
// We've seen all the inserts come through, but we haven't had 4 consistent tags yet
37+
// We've seen all the inserts come through, but we haven't reached
38+
// numConsistent consecutive consistent tags yet
3839
cc.etagChanges = 3
3940
cc.currConsistent = 1
4041

4142
if cc.reachedConsistency(numInserts) {
4243
t.Errorf("Failed: reached consistency (numInserts: %d, currConsistent: %d, etagChanges: %d, timeout: %d)", numInserts, cc.currConsistent, cc.etagChanges, int(cc.timeout.Minutes()))
4344
}
4445

45-
// We've seen all the inserts come through, and it's been consistent 4 times
46-
cc.currConsistent = 4
46+
// We've seen all the inserts come through, and it's been consistent
47+
// numConsistent times
48+
cc.currConsistent = numConsistent
4749

4850
if !cc.reachedConsistency(numInserts) {
4951
t.Errorf("Failed: did not reach consistency (numInserts: %d, currConsistent: %d, etagChanges: %d, timeout: %d)", numInserts, cc.currConsistent, cc.etagChanges, int(cc.timeout.Minutes()))

internal/provider/provider_config_test.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func TestConfigLoadAndValidate_credsJSON(t *testing.T) {
4343
diags := config.loadAndValidate(context.Background())
4444
err = checkDiags(diags)
4545
if err != nil {
46-
t.Fatalf(err.Error())
46+
t.Fatalf("%s", err.Error())
4747
}
4848
}
4949

@@ -56,7 +56,7 @@ func TestConfigLoadAndValidate_credsFromFile(t *testing.T) {
5656
diags := config.loadAndValidate(context.Background())
5757
err := checkDiags(diags)
5858
if err != nil {
59-
t.Fatalf(err.Error())
59+
t.Fatalf("%s", err.Error())
6060
}
6161
}
6262

@@ -77,13 +77,13 @@ func TestAccConfigLoadAndValidate_credsFromEnv(t *testing.T) {
7777
diags := config.loadAndValidate(context.Background())
7878
err := checkDiags(diags)
7979
if err != nil {
80-
t.Fatalf(err.Error())
80+
t.Fatalf("%s", err.Error())
8181
}
8282

8383
diags = checkValidCreds(config)
8484
err = checkDiags(diags)
8585
if err != nil {
86-
t.Fatalf(err.Error())
86+
t.Fatalf("%s", err.Error())
8787
}
8888
}
8989

@@ -95,7 +95,7 @@ func TestConfigLoadAndValidate_credsNoImpersonation(t *testing.T) {
9595
diags := config.loadAndValidate(context.Background())
9696
err := checkDiags(diags)
9797
if err != nil {
98-
t.Fatalf(err.Error())
98+
t.Fatalf("%s", err.Error())
9999
}
100100
}
101101

@@ -109,7 +109,7 @@ func TestConfigOauthScopes_custom(t *testing.T) {
109109
diags := config.loadAndValidate(context.Background())
110110
err := checkDiags(diags)
111111
if err != nil {
112-
t.Fatalf(err.Error())
112+
t.Fatalf("%s", err.Error())
113113
}
114114

115115
if len(config.ClientScopes) != 1 {
@@ -152,12 +152,12 @@ func TestConfigLoadAndValidate_accessToken(t *testing.T) {
152152
diags := gcpConfig.loadAndValidate(context.Background())
153153
err := checkDiags(diags)
154154
if err != nil {
155-
t.Fatalf(err.Error())
155+
t.Fatalf("%s", err.Error())
156156
}
157157

158158
iamCredsService, err := iamcredentials.NewService(context.Background(), option.WithHTTPClient(gcpConfig.client))
159159
if err != nil {
160-
t.Fatalf(err.Error())
160+
t.Fatalf("%s", err.Error())
161161
}
162162
serviceAccount := fmt.Sprintf("projects/-/serviceAccounts/%s", os.Getenv("GOOGLEWORKSPACE_IMPERSONATED_SERVICE_ACCOUNT"))
163163
tokenRequest := &iamcredentials.GenerateAccessTokenRequest{
@@ -166,7 +166,7 @@ func TestConfigLoadAndValidate_accessToken(t *testing.T) {
166166
}
167167
at, err := iamCredsService.Projects.ServiceAccounts.GenerateAccessToken(serviceAccount, tokenRequest).Do()
168168
if err != nil {
169-
t.Fatalf(err.Error())
169+
t.Fatalf("%s", err.Error())
170170
}
171171

172172
config := &apiClient{
@@ -179,13 +179,13 @@ func TestConfigLoadAndValidate_accessToken(t *testing.T) {
179179
diags = config.loadAndValidate(context.Background())
180180
err = checkDiags(diags)
181181
if err != nil {
182-
t.Fatalf(err.Error())
182+
t.Fatalf("%s", err.Error())
183183
}
184184

185185
diags = checkValidCreds(config)
186186
err = checkDiags(diags)
187187
if err != nil {
188-
t.Fatalf(err.Error())
188+
t.Fatalf("%s", err.Error())
189189
}
190190
}
191191

@@ -233,13 +233,13 @@ func TestConfigLoadAndValidate_accessTokenOnly(t *testing.T) {
233233
diags := config.loadAndValidate(context.Background())
234234
err = checkDiags(diags)
235235
if err != nil {
236-
t.Fatalf(err.Error())
236+
t.Fatalf("%s", err.Error())
237237
}
238238

239239
diags = checkValidCredsGroupAdmin(config)
240240
err = checkDiags(diags)
241241
if err != nil {
242-
t.Fatalf(err.Error())
242+
t.Fatalf("%s", err.Error())
243243
}
244244
}
245245

internal/provider/provider_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func googleworkspaceTestClient() (*apiClient, error) {
7575
diags := client.loadAndValidate(context.Background())
7676
if diags.HasError() {
7777
log.Printf("[INFO][SWEEPER_LOG] error loading: %s", diags[0].Summary)
78-
return nil, fmt.Errorf(diags[0].Summary)
78+
return nil, fmt.Errorf("%s", diags[0].Summary)
7979
}
8080

8181
return client, nil

internal/provider/resource_domain_alias_sweeper_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ func testSweepDomainAlias(region string) error {
3232
directoryService, diags := client.NewDirectoryService()
3333
if diags.HasError() {
3434
log.Printf("[INFO][SWEEPER_LOG] Error creating directory service: %s", diags[0].Summary)
35-
return fmt.Errorf(diags[0].Summary)
35+
return fmt.Errorf("%s", diags[0].Summary)
3636
}
3737

3838
domainAliasesService, diags := GetDomainAliasesService(directoryService)
3939
if diags.HasError() {
4040
log.Printf("[INFO][SWEEPER_LOG] Error getting domain aliases service: %s", diags[0].Summary)
41-
return fmt.Errorf(diags[0].Summary)
41+
return fmt.Errorf("%s", diags[0].Summary)
4242
}
4343

4444
domainAliases, err := domainAliasesService.List(client.Customer).Do()

0 commit comments

Comments
 (0)