Repository: diggerhq/digger
Pull request #290 (2023-05-22 21:34:26)

fix(deps): update module github.com/aws/aws-sdk-go to v1.44.268
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [github.com/aws/aws-sdk-go](https://togithub.com/aws/aws-sdk-go) | require | patch | `v1.44.266` -> `v1.44.268` |

---

### Release Notes

<details>
<summary>aws/aws-sdk-go</summary>

### [`v1.44.268`](https://togithub.com/aws/aws-sdk-go/blob/HEAD/CHANGELOG.md#Release-v144268-2023-05-23)

[Compare Source](https://togithub.com/aws/aws-sdk-go/compare/v1.44.267...v1.44.268)

\===

##### Service Client Updates

-   `service/fms`: Updates service API
-   `service/sagemaker`: Updates service API and documentation
    -   Added ModelNameEquals, ModelPackageVersionArnEquals in request and ModelName, SamplePayloadUrl, ModelPackageVersionArn in response of ListInferenceRecommendationsJobs API. Added Invocation timestamps in response of DescribeInferenceRecommendationsJob API & ListInferenceRecommendationsJobSteps API.
-   `service/translate`: Updates service API and documentation

### [`v1.44.267`](https://togithub.com/aws/aws-sdk-go/blob/HEAD/CHANGELOG.md#Release-v144267-2023-05-22)

[Compare Source](https://togithub.com/aws/aws-sdk-go/compare/v1.44.266...v1.44.267)

\===

##### Service Client Updates

-   `service/backup`: Updates service API and documentation
-   `service/pinpoint`: Updates service documentation
    -   Amazon Pinpoint is deprecating the tags parameter in the UpdateSegment, UpdateCampaign, UpdateEmailTemplate, UpdateSmsTemplate, UpdatePushTemplate, UpdateInAppTemplate and UpdateVoiceTemplate. Amazon Pinpoint will end support tags parameter by May 22, 2023.
-   `service/quicksight`: Updates service API, documentation, and paginators
    -   Add support for Asset Bundle, Geospatial Heatmaps.

##### SDK Bugs

-   `rest`: Revert removing unnecessary path normalization behavior.
    -   This behavior would mutate request paths with URI-encoded characters, potentially resulting in misrouted requests.
-   `config`: Revert deprecating `DisableRestProtocolURICleaning` config setting.
    -   This setting will have an effect again. REST-protocol paths will now be normalized after serialization.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/diggerhq/digger).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNS45OC4wIiwidXBkYXRlZEluVmVyIjoiMzUuOTguNCIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->



Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6063c7da..d762546b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -11,6 +11,7 @@ and we would be happy to set you up.
 - [How to contribute](#how-to-contribute)
 - [Coding conventions](#coding-conventions)
 - [Submitting a pull request](#submitting-a-pull-request)
+- [Release Process](#release-process)
 - [Code of Conduct](#code-of-conduct)
 - [License](#license)
 
@@ -38,15 +39,25 @@ We strive to maintain a consistent coding style throughout the project. Please f
 
 ## Submitting a pull request
 When you have made changes to the codebase that you would like to contribute back, please follow these steps:
-1. Fork the repository and create a new branch from `main`.
+1. Fork the repository and create a new branch from `develop`.
 2. Make your changes and ensure that the code passes all tests.
 3. Write tests for your changes, if applicable.
 4. Update the documentation to reflect your changes, if applicable.
-5. Submit a pull request to the `main` branch.
+5. Submit a pull request to the `develop` branch.
    We will review your pull request as soon as possible. Please be patient and open to feedback. We appreciate your contributions!
 
+## Release Process
+**NOTE: The default branch `@develop` is not guaranteed to be stable and you should always use published release versions in your testing and production.**
+
+- All pull requests are merged to the default develop branch after initial unit tests and integration tests are passing and required code review requirements are met.
+- We checkout a pre-release branch to prepare for an upcoming release with the pattern `prerelease-0.1.xx`.
+- We perform additional manual and automated tests in this branch to make sure there are no regressions.
+- Once we are ready we tag the head of our release branch and perform a release on it.
+- Tagged releases are published as actions and they are the most suitable to be used in production.
+
+
 ## Code of Conduct
 We expect all contributors to follow our [Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) when participating in our community. Please read it carefully before contributing.
 
 ## License
-Digger is released under the [Apache License](LICENSE). By contributing to this project, you agree to license your contributions under the same license.
\ No newline at end of file
+Digger is released under the [Apache License](LICENSE). By contributing to this project, you agree to license your contributions under the same license.
diff --git a/cmd/digger/main.go b/cmd/digger/main.go
index 67622f46..e5f50610 100644
--- a/cmd/digger/main.go
+++ b/cmd/digger/main.go
@@ -8,6 +8,7 @@ import (
 	dg_github "digger/pkg/github"
 	"digger/pkg/gitlab"
 	"digger/pkg/models"
+	"digger/pkg/usage"
 	"digger/pkg/utils"
 	"fmt"
 	"github.com/google/go-github/v51/github"
@@ -20,9 +21,9 @@ func gitHubCI(lock utils.Lock) {
 	println("Using GitHub.")
 	githubRepositoryOwner := os.Getenv("GITHUB_REPOSITORY_OWNER")
 	if githubRepositoryOwner != "" {
-		utils.SendUsageRecord(githubRepositoryOwner, "log", "initialize")
+		usage.SendUsageRecord(githubRepositoryOwner, "log", "initialize")
 	} else {
-		utils.SendUsageRecord("", "log", "non github initialisation")
+		usage.SendUsageRecord("", "log", "non github initialisation")
 	}
 
 	ghToken := os.Getenv("GITHUB_TOKEN")
@@ -265,7 +266,7 @@ func logCommands(projectCommands []digger.ProjectCommand) {
 
 func reportErrorAndExit(repoOwner string, message string, exitCode int) {
 	fmt.Printf(message)
-	err := utils.SendLogRecord(repoOwner, message)
+	err := usage.SendLogRecord(repoOwner, message)
 	if err != nil {
 		fmt.Printf("Failed to send log record. %s\n", err)
 	}
diff --git a/go.mod b/go.mod
index b707f4a1..38baba4a 100644
--- a/go.mod
+++ b/go.mod
@@ -6,14 +6,13 @@ require (
 	cloud.google.com/go/storage v1.30.1
 	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0
 	github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1
-	github.com/aws/aws-sdk-go v1.44.266
+	github.com/aws/aws-sdk-go v1.44.268
 	github.com/bmatcuk/doublestar/v4 v4.6.0
 	github.com/caarlos0/env/v7 v7.1.0
-	github.com/caarlos0/env/v8 v8.0.0
 	github.com/google/go-github/v51 v51.0.0
 	github.com/google/uuid v1.3.0
-	github.com/stretchr/testify v1.8.3
-	github.com/xanzy/go-gitlab v0.83.0
+	github.com/stretchr/testify v1.8.4
+	github.com/xanzy/go-gitlab v0.84.0
 	gopkg.in/yaml.v3 v3.0.1
 )
 
@@ -39,7 +38,6 @@ require (
 	github.com/kr/pretty v0.1.0 // indirect
 	github.com/kylelemons/godebug v1.1.0 // indirect
 	github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
-	github.com/stretchr/objx v0.5.0 // indirect
 	go.opencensus.io v0.24.0 // indirect
 	golang.org/x/crypto v0.7.0 // indirect
 	golang.org/x/net v0.9.0 // indirect
diff --git a/go.sum b/go.sum
index 3af8df2f..fc652126 100644
--- a/go.sum
+++ b/go.sum
@@ -23,24 +23,15 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDm
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
 github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
-github.com/aws/aws-sdk-go v1.44.260 h1:78IJkDpDPXvLXvIkNAKDP/i3z8Vj+3sTAtQYw/v/2o8=
-github.com/aws/aws-sdk-go v1.44.260/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/aws/aws-sdk-go v1.44.261 h1:PcTMX/QVk+P3yh2n34UzuXDF5FS2z5Lse2bt+r3IpU4=
-github.com/aws/aws-sdk-go v1.44.261/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/aws/aws-sdk-go v1.44.262 h1:gyXpcJptWoNkK+DiAiaBltlreoWKQXjAIh6FRh60F+I=
-github.com/aws/aws-sdk-go v1.44.262/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/aws/aws-sdk-go v1.44.263 h1:Dkt5fcdtL8QtK3cz0bOTQ84m9dGx+YDeTsDl+wY2yW4=
-github.com/aws/aws-sdk-go v1.44.263/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/aws/aws-sdk-go v1.44.264 h1:5klL62ebn6uv3oJ0ixF7K12hKItj8lV3QqWeQPlkFSs=
-github.com/aws/aws-sdk-go v1.44.264/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/aws/aws-sdk-go v1.44.266 h1:MWd775dcYf7NrwgcHLtlsIbWoWkX8p4vomfNHr88zH0=
 github.com/aws/aws-sdk-go v1.44.266/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go v1.44.268 h1:WoK20tlAvsvQzTcE6TajoprbXmTbcud6MjhErL4P/38=
+github.com/aws/aws-sdk-go v1.44.268/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
 github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
 github.com/caarlos0/env/v7 v7.1.0 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
 github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E=
-github.com/caarlos0/env/v8 v8.0.0/go.mod h1:7K4wMY9bH0esiXSSHlfHLX5xKGQMnkH5Fk4TDSSSzfo=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY=
@@ -112,9 +103,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
-github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
-github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -123,18 +111,19 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
 github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/xanzy/go-gitlab v0.83.0 h1:37p0MpTPNbsTMKX/JnmJtY8Ch1sFiJzVF342+RvZEGw=
 github.com/xanzy/go-gitlab v0.83.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
+github.com/xanzy/go-gitlab v0.84.0 h1:PdpCaskQSgcVDsx21c6ikf8Rfyo7SNtFAJwP9PrbCFE=
+github.com/xanzy/go-gitlab v0.84.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
diff --git a/pkg/configuration/digger_config.go b/pkg/configuration/digger_config.go
index 6c867960..7458a258 100644
--- a/pkg/configuration/digger_config.go
+++ b/pkg/configuration/digger_config.go
@@ -1,6 +1,7 @@
 package configuration
 
 import (
+	"digger/pkg/utils"
 	"errors"
 	"fmt"
 	"github.com/bmatcuk/doublestar/v4"
@@ -8,7 +9,6 @@ import (
 	"os"
 	"path"
 	"path/filepath"
-	"strings"
 )
 
 type WorkflowConfiguration struct {
@@ -44,11 +44,13 @@ type GenerateProjectsConfig struct {
 }
 
 type Project struct {
-	Name       string `yaml:"name"`
-	Dir        string `yaml:"dir"`
-	Workspace  string `yaml:"workspace"`
-	Terragrunt bool   `yaml:"terragrunt"`
-	Workflow   string `yaml:"workflow"`
+	Name            string   `yaml:"name"`
+	Dir             string   `yaml:"dir"`
+	Workspace       string   `yaml:"workspace"`
+	Terragrunt      bool     `yaml:"terragrunt"`
+	Workflow        string   `yaml:"workflow"`
+	IncludePatterns []string `yaml:"include_patterns,omitempty"`
+	ExcludePatterns []string `yaml:"exclude_patterns,omitempty"`
 }
 
 type Stage struct {
@@ -337,12 +339,14 @@ func (c *DiggerConfig) GetProjects(projectName string) []Project {
 func (c *DiggerConfig) GetModifiedProjects(changedFiles []string) []Project {
 	var result []Project
 	for _, project := range c.Projects {
-		for _, file := range changedFiles {
-			absoluteFile, _ := filepath.Abs(path.Join("/", file))
-			absoluteDir, _ := filepath.Abs(path.Join("/", project.Dir))
-
-			//fmt.Printf("absoluteFile: %s, absoluteDir: %s \n", absoluteFile, absoluteDir)
-			if strings.HasPrefix(absoluteFile, absoluteDir) {
+		for _, changedFile := range changedFiles {
+			// we append ** to make our directory a globable pattern
+			projectDirPattern := path.Join(project.Dir, "**")
+			includePatterns := project.IncludePatterns
+			excludePatterns := project.ExcludePatterns
+			// all our patterns are the globale dir pattern + the include patterns specified by user
+			allIncludePatterns := append([]string{projectDirPattern}, includePatterns...)
+			if utils.MatchIncludeExcludePatternsToFile(changedFile, allIncludePatterns, excludePatterns) {
 				result = append(result, project)
 				break
 			}
diff --git a/pkg/digger/digger.go b/pkg/digger/digger.go
index c4b822f9..1a7d5ec8 100644
--- a/pkg/digger/digger.go
+++ b/pkg/digger/digger.go
@@ -6,6 +6,7 @@ import (
 	"digger/pkg/configuration"
 	"digger/pkg/models"
 	"digger/pkg/terraform"
+	"digger/pkg/usage"
 	"digger/pkg/utils"
 	"encoding/json"
 	"errors"
@@ -102,7 +103,7 @@ func RunCommandsPerProject(commandsPerProject []ProjectCommand, repoOwner string
 			}
 			switch command {
 			case "digger plan":
-				utils.SendUsageRecord(repoOwner, eventName, "plan")
+				usage.SendUsageRecord(repoOwner, eventName, "plan")
 				ciService.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/plan")
 				planPerformed, err := diggerExecutor.Plan(prNumber)
 				if err != nil {
@@ -113,7 +114,7 @@ func RunCommandsPerProject(commandsPerProject []ProjectCommand, repoOwner string
 					ciService.SetStatus(prNumber, "success", projectCommands.ProjectName+"/plan")
 				}
 			case "digger apply":
-				utils.SendUsageRecord(repoName, eventName, "apply")
+				usage.SendUsageRecord(repoName, eventName, "apply")
 				ciService.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/apply")
 				applyPerformed, err := diggerExecutor.Apply(prNumber)
 				if err != nil {
@@ -125,13 +126,13 @@ func RunCommandsPerProject(commandsPerProject []ProjectCommand, repoOwner string
 					appliesPerProject[projectCommands.ProjectName] = true
 				}
 			case "digger unlock":
-				utils.SendUsageRecord(repoOwner, eventName, "unlock")
+				usage.SendUsageRecord(repoOwner, eventName, "unlock")
 				err := diggerExecutor.Unlock(prNumber)
 				if err != nil {
 					return false, fmt.Errorf("failed to unlock project. %v", err)
 				}
 			case "digger lock":
-				utils.SendUsageRecord(repoOwner, eventName, "lock")
+				usage.SendUsageRecord(repoOwner, eventName, "lock")
 				err := diggerExecutor.Lock(prNumber)
 				if err != nil {
 					return false, fmt.Errorf("failed to lock project. %v", err)
diff --git a/pkg/gitlab/gitlab.go b/pkg/gitlab/gitlab.go
index ec53e767..dea32a43 100644
--- a/pkg/gitlab/gitlab.go
+++ b/pkg/gitlab/gitlab.go
@@ -5,14 +5,14 @@ import (
 	"digger/pkg/configuration"
 	"digger/pkg/digger"
 	"digger/pkg/terraform"
+	"digger/pkg/usage"
 	"digger/pkg/utils"
 	"fmt"
+	"github.com/caarlos0/env/v7"
+	go_gitlab "github.com/xanzy/go-gitlab"
 	"log"
 	"path"
 	"strings"
-
-	"github.com/caarlos0/env/v7"
-	go_gitlab "github.com/xanzy/go-gitlab"
 )
 
 // based on https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
@@ -368,7 +368,7 @@ func RunCommandsPerProject(commandsPerProject []digger.ProjectCommand, gitLabCon
 			eventName := ""
 			switch command {
 			case "digger plan":
-				utils.SendUsageRecord(repoOwner, eventName, "plan")
+				usage.SendUsageRecord(repoOwner, eventName, "plan")
 				service.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/plan")
 				planPerformed, err := diggerExecutor.Plan(prNumber)
 				if err != nil {
@@ -382,7 +382,7 @@ func RunCommandsPerProject(commandsPerProject []digger.ProjectCommand, gitLabCon
 					service.SetStatus(prNumber, "success", projectCommands.ProjectName+"/plan")
 				}
 			case "digger apply":
-				utils.SendUsageRecord(repoName, eventName, "apply")
+				usage.SendUsageRecord(repoName, eventName, "apply")
 				service.SetStatus(prNumber, "pending", projectCommands.ProjectName+"/apply")
 				applyPerformed, err := diggerExecutor.Apply(prNumber)
 				if err != nil {
@@ -396,13 +396,13 @@ func RunCommandsPerProject(commandsPerProject []digger.ProjectCommand, gitLabCon
 					appliesPerProject[projectCommands.ProjectName] = true
 				}
 			case "digger unlock":
-				utils.SendUsageRecord(repoOwner, eventName, "unlock")
+				usage.SendUsageRecord(repoOwner, eventName, "unlock")
 				err := diggerExecutor.Unlock(prNumber)
 				if err != nil {
 					return false, fmt.Errorf("failed to unlock project. %v", err)
 				}
 			case "digger lock":
-				utils.SendUsageRecord(repoOwner, eventName, "lock")
+				usage.SendUsageRecord(repoOwner, eventName, "lock")
 				err := diggerExecutor.Lock(prNumber)
 				if err != nil {
 					return false, fmt.Errorf("failed to lock project. %v", err)
diff --git a/pkg/utils/usage.go b/pkg/usage/usage.go
similarity index 99%
rename from pkg/utils/usage.go
rename to pkg/usage/usage.go
index d953438e..dba316d8 100644
--- a/pkg/utils/usage.go
+++ b/pkg/usage/usage.go
@@ -1,4 +1,4 @@
-package utils
+package usage
 
 import (
 	"bytes"
diff --git a/pkg/utils/io.go b/pkg/utils/io.go
index d33fe212..6cd120b5 100644
--- a/pkg/utils/io.go
+++ b/pkg/utils/io.go
@@ -3,8 +3,12 @@ package utils
 import (
 	"archive/zip"
 	"bytes"
+	"github.com/bmatcuk/doublestar/v4"
 	"io"
 	"io/ioutil"
+	"log"
+	"path"
+	"path/filepath"
 	"strings"
 )
 
@@ -66,3 +70,46 @@ func (z *Zipper) GetFileFromZip(zipFile string, filename string) (string, error)
 
 	return "", nil
 }
+
+func NormalizeFileName(fileName string) string {
+	res, err := filepath.Abs(path.Join("/", fileName))
+	if err != nil {
+		log.Fatalf("Failed to convert path to absolute: %v", err)
+	}
+	return res
+}
+
+func MatchIncludeExcludePatternsToFile(fileToMatch string, includePatterns []string, excludePatterns []string) bool {
+	fileToMatch = NormalizeFileName(fileToMatch)
+	for i, _ := range includePatterns {
+		includePatterns[i] = NormalizeFileName(includePatterns[i])
+	}
+	for i, _ := range excludePatterns {
+		excludePatterns[i] = NormalizeFileName(excludePatterns[i])
+	}
+
+	matching := false
+	for _, ipattern := range includePatterns {
+		isMatched, err := doublestar.PathMatch(ipattern, fileToMatch)
+		if err != nil {
+			log.Fatalf("Failed to match modified files (%v, %v): Error: %v", fileToMatch, ipattern, err)
+		}
+		if isMatched {
+			matching = true
+			break
+		}
+	}
+
+	for _, epattern := range excludePatterns {
+		excluded, err := doublestar.PathMatch(epattern, fileToMatch)
+		if err != nil {
+			log.Fatalf("Failed to match modified files (%v, %v): Error: %v", fileToMatch, epattern, err)
+		}
+		if excluded {
+			matching = false
+			break
+		}
+	}
+
+	return matching
+}


Test patch:
diff --git a/pkg/utils/usage_test.go b/pkg/usage/usage_test.go
similarity index 95%
rename from pkg/utils/usage_test.go
rename to pkg/usage/usage_test.go
index 48a46c27..5e7555a0 100644
--- a/pkg/utils/usage_test.go
+++ b/pkg/usage/usage_test.go
@@ -1,4 +1,4 @@
-package utils
+package usage
 
 import (
 	"github.com/stretchr/testify/assert"
diff --git a/pkg/utils/io_test.go b/pkg/utils/io_test.go
index 23f91155..17767e9f 100644
--- a/pkg/utils/io_test.go
+++ b/pkg/utils/io_test.go
@@ -77,3 +77,40 @@ func TestGetFileFromZipNoFileExists(t *testing.T) {
 	// Clean up the test files.
 	os.Remove(zipFileName)
 }
+
+func TestNormalizeFileName(t *testing.T) {
+	type NormTest struct {
+		input, expectedOutput string // input and expected normalized output
+	}
+	var normTests = []NormTest{
+		{"my/directory", "/my/directory"},
+		{"./my/directory", "/my/directory"},
+	}
+	for _, tt := range normTests {
+		res := NormalizeFileName(tt.input)
+		assert.Equal(t, tt.expectedOutput, res)
+	}
+}
+
+func TestMatchIncludeExcludePatternsToFile(t *testing.T) {
+	type MatchTest struct {
+		fileToMatch     string
+		includePatterns []string
+		excludePatterns []string
+		expectedResult  bool
+	}
+	var normTests = []MatchTest{
+		{"dev/main.tf", []string{"dev/**"}, []string{}, true},
+		{"dev/main.tf", []string{"./dev/**"}, []string{}, true},
+		{"dev/main.tf", []string{"dev/**"}, []string{"dev/"}, true},
+		{"dev/main.tf", []string{"prod/**"}, []string{"dev/"}, false},
+		{"modules/moduleA/main.tf", []string{"dev**", "modules/**"}, []string{"dev/"}, true},
+		{"modules/moduleA/main.tf", []string{"dev**", "./modules/**"}, []string{"dev/"}, true},
+		{"modules/moduleA/main.tf", []string{"dev**"}, []string{"dev/"}, false},
+		{"modules/moduleA/main.tf", []string{"dev**", "modules/**"}, []string{"modules/moduleA/**"}, false},
+	}
+	for _, tt := range normTests {
+		res := MatchIncludeExcludePatternsToFile(tt.fileToMatch, tt.includePatterns, tt.excludePatterns)
+		assert.Equal(t, tt.expectedResult, res)
+	}
+}