From cd182b4839b6e2ed359a5e27b6bc4f9b6196d2a0 Mon Sep 17 00:00:00 2001 From: Douglas Parsons Date: Mon, 18 Jul 2022 17:53:08 +0100 Subject: [PATCH 1/4] Add windows to test workflow --- .github/workflows/test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1088da3e..49b89754 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,15 +38,18 @@ jobs: test: name: Matrix Test needs: build - runs-on: ubuntu-latest timeout-minutes: 15 strategy: max-parallel: 1 fail-fast: false matrix: + os: + - "ubuntu-latest" + - "windows-latest" terraform: - "1.1.*" - "1.0.*" + runs-on: ${{ matrix.os }} steps: - name: Set up Go uses: actions/setup-go@v2 From ca2bf2008ec64e7798b3a4bd01b0d5378e719a1f Mon Sep 17 00:00:00 2001 From: Douglas Parsons Date: Wed, 20 Jul 2022 14:24:43 +0100 Subject: [PATCH 2/4] Prevent duplicate test workflows --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 49b89754..0ff4f7c6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,11 @@ on: # TODO - periodically run on a cron to detect API drift. # schedule: # - cron: '0 13 * * *' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + jobs: build: name: Build From f83cd02971caa3ab22b907f3f5a1ed629e43b8be Mon Sep 17 00:00:00 2001 From: Douglas Parsons Date: Wed, 20 Jul 2022 15:44:33 +0100 Subject: [PATCH 3/4] Normalise content \r\n to \n --- vercel/data_source_file.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vercel/data_source_file.go b/vercel/data_source_file.go index 723e2db9..6714d3ac 100644 --- a/vercel/data_source_file.go +++ b/vercel/data_source_file.go @@ -1,6 +1,7 @@ package vercel import ( + "bytes" "context" "crypto/sha1" "encoding/hex" @@ -12,6 +13,11 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) +func removeCRLF(content []byte) []byte { + bytes.ReplaceAll(content, []byte("\r\n"), []byte("\n")) + return content +} + type dataSourceFileType struct{} // GetSchema returns the schema information for a file data source @@ -81,6 +87,7 @@ func (r dataSourceFile) Read(ctx context.Context, req tfsdk.ReadDataSourceReques ) return } + content = removeCRLF(content) rawSha := sha1.Sum(content) sha := hex.EncodeToString(rawSha[:]) From 5a2ec14aac50c77a96f22ba8219444ac490c756b Mon Sep 17 00:00:00 2001 From: Douglas Parsons Date: Wed, 20 Jul 2022 15:54:26 +0100 Subject: [PATCH 4/4] Fix test names and temporarily shortcut CI --- .github/workflows/test.yml | 3 +- vercel/data_source_file.go | 9 ++++- vercel/data_source_file_test.go | 2 +- vercel/data_source_project_directory.go | 1 + vercel/data_source_project_directory_test.go | 7 ++-- vercel/resource_deployment.go | 2 +- vercel/resource_deployment_model.go | 41 ++++++++++++++------ vercel/resource_deployment_test.go | 1 - 8 files changed, 45 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0ff4f7c6..27f22d3d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,6 @@ jobs: test: name: Matrix Test - needs: build timeout-minutes: 15 strategy: max-parallel: 1 @@ -80,4 +79,4 @@ jobs: VERCEL_TERRAFORM_TESTING_BITBUCKET_REPO: "dglsparsons-test/test" VERCEL_TERRAFORM_TESTING_DOMAIN: "dgls.dev" run: | - go test -v -cover ./... + go test ./... diff --git a/vercel/data_source_file.go b/vercel/data_source_file.go index 6714d3ac..2713db17 100644 --- a/vercel/data_source_file.go +++ b/vercel/data_source_file.go @@ -13,9 +13,14 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) +/* +* To have the content hash and file sizes remain consistent between different operating systems +* (important as this prevents spurious file-changes, and thus spurious file uploads), make sure +* the file content handles line-endings consistently, regardless of the host platform. +* The simplest way to achieve this is just to replace CRLF with LF. + */ func removeCRLF(content []byte) []byte { - bytes.ReplaceAll(content, []byte("\r\n"), []byte("\n")) - return content + return bytes.ReplaceAll(content, []byte("\r\n"), []byte("\n")) } type dataSourceFileType struct{} diff --git a/vercel/data_source_file_test.go b/vercel/data_source_file_test.go index 31c77639..dacd6ea3 100644 --- a/vercel/data_source_file_test.go +++ b/vercel/data_source_file_test.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAcc_FileDataSource(t *testing.T) { +func TestAcc_DataSourceFile(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/vercel/data_source_project_directory.go b/vercel/data_source_project_directory.go index a3ee0fcb..2b8018c6 100644 --- a/vercel/data_source_project_directory.go +++ b/vercel/data_source_project_directory.go @@ -111,6 +111,7 @@ func (r dataSourceProjectDirectory) Read(ctx context.Context, req tfsdk.ReadData ) return } + content = removeCRLF(content) rawSha := sha1.Sum(content) sha := hex.EncodeToString(rawSha[:]) diff --git a/vercel/data_source_project_directory_test.go b/vercel/data_source_project_directory_test.go index e59270ed..1f970aae 100644 --- a/vercel/data_source_project_directory_test.go +++ b/vercel/data_source_project_directory_test.go @@ -1,12 +1,13 @@ package vercel_test import ( + "path/filepath" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAcc_ProjectDirectoryDataSource(t *testing.T) { +func TestAcc_DataSourceProjectDirectory(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -16,8 +17,8 @@ func TestAcc_ProjectDirectoryDataSource(t *testing.T) { Config: testAccProjectDirectoryConfig(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("data.vercel_project_directory.test", "path", "example"), - resource.TestCheckResourceAttr("data.vercel_project_directory.test", "files.example/index.html", "60~9d3fedcc87ac72f54e75d4be7e06d0a6f8497e68"), - resource.TestCheckNoResourceAttr("data.vercel_project_directory.test", "files.example/file2.html"), + resource.TestCheckResourceAttr("data.vercel_project_directory.test", filepath.Join("files.example", "index.html"), "60~9d3fedcc87ac72f54e75d4be7e06d0a6f8497e68"), + resource.TestCheckNoResourceAttr("data.vercel_project_directory.test", filepath.Join("files.example", "file2.html")), ), }, }, diff --git a/vercel/resource_deployment.go b/vercel/resource_deployment.go index 5635664a..855b298d 100644 --- a/vercel/resource_deployment.go +++ b/vercel/resource_deployment.go @@ -274,7 +274,7 @@ func (r resourceDeployment) Create(ctx context.Context, req tfsdk.CreateResource } err = r.p.client.CreateFile(ctx, client.CreateFileRequest{ - Filename: f.File, + Filename: normaliseFilename(f.File, plan.PathPrefix), SHA: f.Sha, Content: string(content), TeamID: plan.TeamID.Value, diff --git a/vercel/resource_deployment_model.go b/vercel/resource_deployment_model.go index ad5b3c86..b61723f2 100644 --- a/vercel/resource_deployment_model.go +++ b/vercel/resource_deployment_model.go @@ -2,6 +2,7 @@ package vercel import ( "fmt" + "path/filepath" "strconv" "strings" @@ -100,6 +101,30 @@ func (p *ProjectSettings) fillNulls() *ProjectSettings { } } +/* + * The files uploaded to Vercel need to have some minor adjustments: + * - Legacy behaviour was that any upward navigation ("../") was stripped from the + * start of a file path. + * - Newer behaviour introduced a `path_prefix` that could be specified, that would + * control what part of a relative path to files should be removed prior to uploading + * into Vercel. + * - We want to support this regardless of path separator, the simplest way to do + * this is to ensure all paths are converted to forward slashes, and settings should + * be specified using forward slashes. + * See https://github.com/vercel/terraform-provider-vercel/issues/14#issuecomment-1103973603 + * for additional context on the first two points. + */ +func normaliseFilename(filename string, pathPrefix types.String) string { + filename = filepath.ToSlash(filename) + if pathPrefix.Unknown || pathPrefix.Null { + for strings.HasPrefix(filename, "../") { + return strings.TrimPrefix(filename, "../") + } + } + + return strings.TrimPrefix(filename, filepath.ToSlash(pathPrefix.Value)) +} + // getFiles is a helper for turning the terraform deployment state into a set of client.DeploymentFile // structs, ready to hit the API with. It also returns a map of files by sha, which is used to quickly // look up any missing SHAs from the create deployment resposnse. @@ -118,25 +143,19 @@ func getFiles(unparsedFiles map[string]string, pathPrefix types.String) ([]clien } sha := sizeSha[1] - untrimmedFilename := filename - if pathPrefix.Unknown || pathPrefix.Null { - for strings.HasPrefix(filename, "../") { - filename = strings.TrimPrefix(filename, "../") - } - } else { - filename = strings.TrimPrefix(filename, pathPrefix.Value) - } file := client.DeploymentFile{ - File: filename, + File: normaliseFilename(filename, pathPrefix), Sha: sha, Size: size, } files = append(files, file) /* The API can return a set of missing files. When this happens, we want the path name - * complete with the original, untrimmed prefix. */ + * complete with the original, untrimmed prefix. This also needs to use the hosts + * path separator. This is so we can read the file. + */ filesBySha[sha] = client.DeploymentFile{ - File: untrimmedFilename, + File: filename, Sha: sha, Size: size, } diff --git a/vercel/resource_deployment_test.go b/vercel/resource_deployment_test.go index cda07433..b639aa6b 100644 --- a/vercel/resource_deployment_test.go +++ b/vercel/resource_deployment_test.go @@ -173,7 +173,6 @@ func TestAcc_DeploymentWithPathPrefix(t *testing.T) { } func TestAcc_DeploymentWithDeleteOnDestroy(t *testing.T) { - t.Parallel() projectSuffix := acctest.RandString(16) extraConfig := "delete_on_destroy = true" deploymentID := ""