Repository: gphotosuploader/gphotos-uploader-cli
Pull request #438 (2024-02-24 11:04:51)

Deprecate the 'auto:' configuration option
**What issue type does this pull request address?** (keep at least one, remove the others)  
/kind enhancement


**What is this pull request for? Which issues does it resolve?** (use `resolves #<issue_number>` if possible)  
With the inclusion of the `template:` configuration option, the `auto:folderName`  and `auto:folderPath` are deprecated. In the future 5.x version it will be removed.


**Does this pull request has user-facing changes?** (e.g. config changes, new/modified commands, new/modified flags)  
Deprecation messages are in place.


Patch:
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 8177fa0..f941405 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -9,6 +9,11 @@ on:
   pull_request:
     paths:
       - '**.go'
+
+env:
+    # it should match the version in the Makefile file.
+    GOLANGCI_LINT_VERSION: 'v1.56.2'
+
 jobs:
   golangci:
     name: Linter code
@@ -21,4 +26,4 @@ jobs:
       - name: golangci-lint
         uses: golangci/golangci-lint-action@v4
         with:
-          version: v1.55.0
+            version: ${{ env.GOLANGCI_LINT_VERSION }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ffa8da5..c135e36 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/) and this project adheres to [Semantic Versioning](https://semver.org/).
 
+## 4.5.0
+### Added
+- Support for the latest published Go version (1.22). This project will maintain compatibility with the latest **two major versions** published.
+
+### Changed
+- Bump `golang.org/x/oauth2` to version 0.17.0
+- Bump `gphotosuploader/google-photos-api-client-go/v3` to version 3.0.5
+
+### Deprecated
+- The `auto:folderName` and `auto:folderPath` options are deprecated in favor of the `template:%_directory%` and `template:%_folderpath%` options. See [documentation](https://gphotosuploader.github.io/gphotos-uploader-cli/#/configuration?id=customized-template-template).
+
+
 ## 4.4.0
 ### Added
 - Option to customize Album names by introducing `template`. Thanks to [@WACKYprog](https://github.com/WACKYprog) ([#431][i431])
diff --git a/Makefile b/Makefile
index caa0c12..3f350b5 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ TMP_DIR ?= .tmp
 COVERAGE_FILE := $(TMP_DIR)/coverage.txt
 COVERAGE_HTML_FILE := $(TMP_DIR)/coverage.html
 GOLANGCI := $(TMP_DIR)/golangci-lint
-GOLANGCI_VERSION := 1.55.0
+GOLANGCI_VERSION := 1.56.2
 
 # set how to open files based on OS and ARCH.
 UNAME_OS := $(shell uname -s)
diff --git a/README.md b/README.md
index 5cfe06b..1a94387 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 Tool to mass upload media folders to your Google Photos account and manage it using a CLI.
 
 [![Go Report Card](https://goreportcard.com/badge/github.com/gphotosuploader/gphotos-uploader-cli)](https://goreportcard.com/report/github.com/gphotosuploader/gphotos-uploader-cli)
-[![codebeat badge](https://codebeat.co/badges/9f3561ad-2838-456e-bc92-68988eeb376b)](https://codebeat.co/projects/github-com-gphotosuploader-gphotos-uploader-cli-main)
+[![codebeat badge](https://codebeat.co/badges/534fbb3c-03fd-4cf1-882c-1d7389c32ab6)](https://codebeat.co/projects/github-com-gphotosuploader-gphotos-uploader-cli-main)
 [![codecov](https://codecov.io/gh/gphotosuploader/gphotos-uploader-cli/branch/main/graph/badge.svg)](https://codecov.io/gh/gphotosuploader/gphotos-uploader-cli)
 [![GitHub release](https://img.shields.io/github/release/gphotosuploader/gphotos-uploader-cli.svg)](https://github.com/gphotosuploader/gphotos-uploader-cli/releases/latest)
 [![GitHub](https://img.shields.io/github/license/gphotosuploader/gphotos-uploader-cli.svg)](LICENSE)
diff --git a/docs/configuration.md b/docs/configuration.md
index 5180f99..cb26094 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -123,9 +123,11 @@ Google Photos
     └── image-album3-03.jpg
 ```
 
-#### Calculated name from a file path: `auto:`
+#### Calculated name from a file path: `auto:` (deprecated)
 
-##### From parent folder: `auto:folderName`
+This configuration option is deprecated and will be removed in future versions. Use `template:` instead.
+
+##### From parent folder: `auto:folderName` (deprecated)
 
 Setting `auto:folderName` and `SourceFolder: /home/my-user/pictures` will use the name of the folder (within `SourceFolder`), where the item is uploaded from, to set the album name.
 
@@ -142,7 +144,7 @@ Google Photos
     ├── image-album3-02.jpg
     └── image-album3-03.jpg
 ```
-##### From full path: `auto:folderPath` 
+##### From full path: `auto:folderPath` (deprectated)
 
 Setting `auto:folderPath` and `SourceFolder: /home/my-user/pictures` will use the full path of the folder (relative to `SourceFolder`), where the item is uploaded from, to set the album name.
 
diff --git a/go.mod b/go.mod
index bedb087..039b71d 100644
--- a/go.mod
+++ b/go.mod
@@ -1,12 +1,13 @@
 module github.com/gphotosuploader/gphotos-uploader-cli
 
-go 1.20
+go 1.21
 
 require (
 	github.com/99designs/keyring v1.2.2
 	github.com/bmatcuk/doublestar/v2 v2.0.4
 	github.com/facebookgo/symwalk v0.0.0-20150726040526-42004b9f3222
-	github.com/gphotosuploader/google-photos-api-client-go/v3 v3.0.4
+	github.com/golang/mock v1.4.4
+	github.com/gphotosuploader/google-photos-api-client-go/v3 v3.0.5
 	github.com/hjson/hjson-go/v4 v4.4.0
 	github.com/int128/oauth2cli v1.14.0
 	github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213
@@ -28,7 +29,7 @@ require (
 )
 
 require (
-	cloud.google.com/go/compute v1.23.3 // indirect
+	cloud.google.com/go/compute v1.24.0 // indirect
 	cloud.google.com/go/compute/metadata v0.2.3 // indirect
 	github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
 	github.com/danieljoos/wincred v1.2.1 // indirect
@@ -52,9 +53,9 @@ require (
 	github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
 	github.com/mtibben/percent v0.2.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/rivo/uniseg v0.4.4 // indirect
+	github.com/rivo/uniseg v0.4.7 // indirect
 	golang.org/x/sys v0.17.0 // indirect
-	google.golang.org/api v0.156.0 // indirect
+	google.golang.org/api v0.167.0 // indirect
 	google.golang.org/appengine v1.6.8 // indirect
 	google.golang.org/protobuf v1.32.0 // indirect
 	gopkg.in/yaml.v2 v2.3.0 // indirect
diff --git a/go.sum b/go.sum
index 84d673b..40c1bf4 100644
--- a/go.sum
+++ b/go.sum
@@ -19,8 +19,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
 cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
 cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
 cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
-cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
+cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
+cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40=
 cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
@@ -72,7 +72,8 @@ github.com/facebookgo/symwalk v0.0.0-20150726040526-42004b9f3222/go.mod h1:PgrCj
 github.com/facebookgo/testname v0.0.0-20150612200628-5443337c3a12 h1:pKeuUgeuL6jk/FpxSr0ZVL1XEiOmrcWBvB2rKXu0mMI=
 github.com/facebookgo/testname v0.0.0-20150612200628-5443337c3a12/go.mod h1:IYed2VYeQcs7JTN6KiVXjaz6Rv/Qz092Wjc6o5bCJ9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
+github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
+github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -88,6 +89,7 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
 github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
 github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -121,6 +123,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -133,8 +136,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/gphotosuploader/google-photos-api-client-go/v3 v3.0.4 h1:XUITVOnz8Ff00L1X1euNTDRwfhi9PEYSzvfCjm0jk3M=
-github.com/gphotosuploader/google-photos-api-client-go/v3 v3.0.4/go.mod h1:a7t6L5yk9VcEk3Os+hNnYv2fESUkok5ZS5xlei9ZVFg=
+github.com/gphotosuploader/google-photos-api-client-go/v3 v3.0.5 h1:ul1y59g2E9XODDM1TWcE5S3IME9TTmn2pkcuOSibRAg=
+github.com/gphotosuploader/google-photos-api-client-go/v3 v3.0.5/go.mod h1:9+9oOxr10ge/Va53UQ8QP98eNbCcCD7T3bjTQek4D7k=
 github.com/gphotosuploader/googlemirror v0.5.0 h1:9a9CCUnAFo3qHp7U/epmdTiOvAzXCkVq5AQLo8PWBns=
 github.com/gphotosuploader/googlemirror v0.5.0/go.mod h1:L6A+2KW6d/OwjZ5QH2fGXJXsOtR115tj9w+YxdyjfUI=
 github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
@@ -195,8 +198,9 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
 github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/schollz/progressbar/v3 v3.14.1 h1:VD+MJPCr4s3wdhTc7OEJ/Z3dAeBzJ7yKH/P4lC5yRTI=
@@ -211,6 +215,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -295,6 +300,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -430,8 +436,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
 google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
 google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
 google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.156.0 h1:yloYcGbBtVYjLKQe4enCunxvwn3s2w/XPrrhVf6MsvQ=
-google.golang.org/api v0.156.0/go.mod h1:bUSmn4KFO0Q+69zo9CNIDp4Psi6BqM0np0CbzKRSiSY=
+google.golang.org/api v0.167.0 h1:CKHrQD1BLRii6xdkatBDXyKzM0mkawt2QP+H3LtPmSE=
+google.golang.org/api v0.167.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
diff --git a/internal/app/app.go b/internal/app/app.go
index e3c6f93..43be7f0 100644
--- a/internal/app/app.go
+++ b/internal/app/app.go
@@ -74,7 +74,7 @@ func StartServices(ctx context.Context, path string) (*App, error) {
 	}
 
 	app.Logger.Infof("Reading configuration from '%s'", app.configFilename())
-	app.Config, err = config.FromFile(app.fs, app.configFilename())
+	app.Config, err = config.FromFile(app.fs, app.configFilename(), app.Logger)
 	if err != nil {
 		return nil, fmt.Errorf("invalid configuration at '%s': %s", app.configFilename(), err)
 	}
diff --git a/internal/config/config.go b/internal/config/config.go
index 9dfacd8..d3317f6 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -5,6 +5,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"github.com/gphotosuploader/gphotos-uploader-cli/internal/log"
 	"io"
 	"path/filepath"
 	"strings"
@@ -26,12 +27,12 @@ func Create(fs afero.Fs, filename string) (*Config, error) {
 
 // FromFile returns the configuration data read from the specified file.
 // FromFile returns a ParseError{} if the configuration validation fails.
-func FromFile(fs afero.Fs, filename string) (*Config, error) {
+func FromFile(fs afero.Fs, filename string, logger log.Logger) (*Config, error) {
 	cfg, err := readFile(fs, filename)
 	if err != nil {
 		return nil, err
 	}
-	if err := cfg.validate(fs); err != nil {
+	if err := cfg.validate(fs, logger); err != nil {
 		return cfg, err
 	}
 
@@ -68,7 +69,7 @@ func (c Config) SafePrint() string {
 }
 
 // validate validates the current configuration.
-func (c Config) validate(fs afero.Fs) error {
+func (c Config) validate(fs afero.Fs, logger log.Logger) error {
 	if err := c.validateSecretsBackendType(); err != nil {
 		return err
 	}
@@ -78,7 +79,7 @@ func (c Config) validate(fs afero.Fs) error {
 	if err := c.validateAccount(); err != nil {
 		return err
 	}
-	if err := c.validateJobs(fs); err != nil {
+	if err := c.validateJobs(fs, logger); err != nil {
 		return err
 	}
 	return nil
@@ -130,28 +131,60 @@ func (c Config) validateAccount() error {
 	return nil
 }
 
-func (c Config) validateJobs(fs afero.Fs) error {
-	if len(c.Jobs) < 1 {
-		return errors.New("at least one Job must be configured")
+func (c Config) validateJobs(fs afero.Fs, logger log.Logger) error {
+	if err := c.checkJobsExistence(); err != nil {
+		return err
 	}
 
 	for _, job := range c.Jobs {
-		exist, err := afero.DirExists(fs, job.SourceFolder)
-		if err != nil {
-			return fmt.Errorf("option SourceFolder '%s' is invalid, err=%s", job.SourceFolder, err)
-		}
-		if !exist {
-			return fmt.Errorf("folder '%s' does not exist", job.SourceFolder)
+		if err := c.validateJob(fs, job, logger); err != nil {
+			return err
 		}
+	}
+	return nil
+}
 
-		albumErr := ValidateAlbumOption(job.Album)
-		if job.Album != "" && albumErr != nil {
-			return albumErr
-		}
-		// TODO: Check CreateAlbums for backwards compatibility. It should be removed on version 5.x
-		if job.Album == "" && !isValidCreateAlbums(job.CreateAlbums) {
-			return fmt.Errorf("option CreateAlbums is invalid, '%s", job.CreateAlbums)
-		}
+func (c Config) checkJobsExistence() error {
+	if len(c.Jobs) < 1 {
+		return errors.New("at least one Job must be configured")
+	}
+	return nil
+}
+
+func (c Config) validateJob(fs afero.Fs, job FolderUploadJob, logger log.Logger) error {
+	if err := c.checkSourceFolder(fs, job); err != nil {
+		return err
+	}
+
+	if err := validateAlbumOption(job.Album, logger); err != nil {
+		return err
+	}
+
+	if err := c.checkDeprecatedCreateAlbums(job, logger); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c Config) checkDeprecatedCreateAlbums(job FolderUploadJob, logger log.Logger) error {
+	// TODO: 'CreateAlbums' is deprecated. It should be removed on version 5.x
+	if job.CreateAlbums != "" {
+		logger.Warnf("Deprecation Notice: The configuration option 'CreateAlbums' is deprecated and will be removed in a future version. Please update your configuration accordingly.")
+	}
+	if job.Album == "" && !isValidCreateAlbums(job.CreateAlbums) {
+		return fmt.Errorf("option CreateAlbums is invalid, '%s", job.CreateAlbums)
+	}
+	return nil
+}
+
+func (c Config) checkSourceFolder(fs afero.Fs, job FolderUploadJob) error {
+	exist, err := afero.DirExists(fs, job.SourceFolder)
+	if err != nil {
+		return fmt.Errorf("option SourceFolder '%s' is invalid, err=%s", job.SourceFolder, err)
+	}
+	if !exist {
+		return fmt.Errorf("folder '%s' does not exist", job.SourceFolder)
 	}
 	return nil
 }
@@ -184,21 +217,23 @@ func isValidAlbumGenerationMethod(method string) bool {
 	return true
 }
 
-// isValidAlbum checks if the value is a valid Album option.
-func ValidateAlbumOption(value string) error {
+// ValidateAlbumOption checks if the value is a valid Album option.
+func validateAlbumOption(value string, logger log.Logger) error {
 	if value == "" {
-		return fmt.Errorf("option Album could not be empty")
+		return nil
 	}
 
 	before, after, found := strings.Cut(value, ":")
 	if !found || after == "" {
-		return fmt.Errorf("option Album is invalid, '%s.", value)
+		return fmt.Errorf("option Album is invalid, '%s", value)
 	}
 
 	switch before {
 	case "name":
 		return nil
 	case "auto":
+		// TODO: 'auto:' is deprecated. It should be removed on version 5.x
+		logger.Warnf("Deprecation Notice: The configuration option 'auto:%s' is deprecated and will be removed in a future version. Please update your configuration accordingly.", after)
 		if !isValidAlbumGenerationMethod(after) {
 			return fmt.Errorf("option Album is invalid: unknown album generation method '%s'", after)
 		}
diff --git a/internal/config/schema.go b/internal/config/schema.go
index 1d77359..39a5c18 100644
--- a/internal/config/schema.go
+++ b/internal/config/schema.go
@@ -35,8 +35,8 @@ type FolderUploadJob struct {
 	// These are the valid values: "name:", "auto:", "template".
 	//   "name:" : Followed by the album name in Google Photos (album names are not unique, so the first to match
 	//             will be selected)
-	//   "auto:" : Followed either "folderPath" or "folderName" will use an autogenerated album name based on the
-	//             object's folder path or object's folder name.
+	//   "auto:" : (deprecated) Followed either "folderPath" or "folderName" will use an autogenerated album name based on the
+	//             object's folder path or object's folder name. Use `template` instead.
 	//   "template": Followed by a template string that can contain the following predefine tokens and functions:
 	//              Tokens:
 	//                 %_folderpath% - full path of the folder containing the file.


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 56d45a8..a9c0be8 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,11 +11,16 @@ on:
     paths-ignore:
       - 'docs/**'
       - '*.md'
+
+env:
+    # run coverage only with the latest Go version
+    LATEST_GO_VERSION: '1.22'
+
 jobs:
   test-matrix:
     strategy:
       matrix:
-        go-version: ['1.20', '1.21']
+        go-version: ['1.21', '1.22']
         os: [ubuntu-latest, macos-latest]
     runs-on: ${{ matrix.os }}
     steps:
@@ -28,4 +33,8 @@ jobs:
       - name: Run tests
         run: make test
       - name: Send code coverage
+        if: success() && matrix.go == env.LATEST_GO_VERSION && matrix.os == 'ubuntu-latest'
         uses: codecov/codecov-action@v4
+        env:
+          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+        
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 2561a3d..1dc7224 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -1,7 +1,10 @@
 package config_test
 
 import (
+	"fmt"
+	"github.com/gphotosuploader/gphotos-uploader-cli/internal/log"
 	"path/filepath"
+	"strings"
 	"testing"
 
 	"github.com/spf13/afero"
@@ -64,9 +67,9 @@ func TestFromFile(t *testing.T) {
 		isErrExpected bool
 	}{
 		{"Should success with Album's name option", "testdata/valid-config/configWithAlbumNameOption.hjson", "youremail@domain.com", false},
-		{"Should success with Album's auto folderName option", "testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson", "youremail@domain.com", false},
-		{"Should success with Album's auto folderPath option", "testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson", "youremail@domain.com", false},
 		{"Should success with Album's template containing token", "testdata/valid-config/configWithAlbumTemplateToken.hjson", "youremail@domain.com", false},
+		{"Should success with deprecated Album's auto folderName option", "testdata/valid-config/configWithDeprecatedAlbumAutoFolderNameOption.hjson", "youremail@domain.com", false},
+		{"Should success with deprecated Album's auto folderPath option", "testdata/valid-config/configWithDeprecatedAlbumAutoFolderPathOption.hjson", "youremail@domain.com", false},
 		{"Should success with deprecated CreateAlbums option", "testdata/valid-config/configWithDeprecatedCreateAlbumsOption.hjson", "youremail@domain.com", false},
 
 		{"Should fail if config dir does not exist", "testdata/non-existent/config.hjson", "", true},
@@ -88,7 +91,7 @@ func TestFromFile(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			fs := afero.OsFs{}
-			got, err := config.FromFile(fs, tc.path)
+			got, err := config.FromFile(fs, tc.path, log.Discard)
 			if err != nil {
 				t.Log(err)
 			}
@@ -101,6 +104,52 @@ func TestFromFile(t *testing.T) {
 	}
 }
 
+type mockLogger struct {
+	log.Logger
+	messages []string
+}
+
+func (m *mockLogger) Warnf(format string, args ...interface{}) {
+	m.messages = append(m.messages, fmt.Sprintf(format, args...))
+}
+
+func TestDeprecationNotices(t *testing.T) {
+	testCases := []struct {
+		name string
+		path string
+		want string
+	}{
+		{"CreateAlbums option", "testdata/valid-config/configWithDeprecatedCreateAlbumsOption.hjson", "CreateAlbums"},
+		{"auto:folderPath option", "testdata/valid-config/configWithDeprecatedAlbumAutoFolderPathOption.hjson", "auto:folderPath"},
+		{"auto:folderName option", "testdata/valid-config/configWithDeprecatedAlbumAutoFolderNameOption.hjson", "auto:folderName"},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			fs := afero.OsFs{}
+			logger := &mockLogger{}
+			_, err := config.FromFile(fs, tc.path, logger)
+			if err != nil {
+				t.Fatalf("Expected no error, got %v", err)
+			}
+			// Check that the deprecation notice was logged
+			if !contains(logger.messages, tc.want) {
+				t.Errorf("Expected deprecation notice for '%s', got %v", tc.want, logger.messages)
+			}
+		})
+	}
+}
+
+// contains checks if a slice contains a string
+func contains(slice []string, str string) bool {
+	for _, v := range slice {
+		if strings.Contains(v, str) {
+			return true
+		}
+	}
+	return false
+}
+
 func TestConfig_SafePrint(t *testing.T) {
 	cfg := config.Config{
 		APIAppCredentials: config.APIAppCredentials{
diff --git a/internal/config/testdata/valid-config/configWithAlbumNameOption.hjson b/internal/config/testdata/valid-config/configWithAlbumNameOption.hjson
index 1005620..7524446 100644
--- a/internal/config/testdata/valid-config/configWithAlbumNameOption.hjson
+++ b/internal/config/testdata/valid-config/configWithAlbumNameOption.hjson
@@ -10,7 +10,7 @@
   [
     {
       SourceFolder: ./testdata/valid-config
-      Album: auto:folderPath
+      Album: name:albumName
       DeleteAfterUpload: false
       IncludePatterns: []
       ExcludePatterns: []
diff --git a/internal/config/testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson b/internal/config/testdata/valid-config/configWithDeprecatedAlbumAutoFolderNameOption.hjson
similarity index 100%
rename from internal/config/testdata/valid-config/configWithAlbumAutoFolderNameOption.hjson
rename to internal/config/testdata/valid-config/configWithDeprecatedAlbumAutoFolderNameOption.hjson
diff --git a/internal/config/testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson b/internal/config/testdata/valid-config/configWithDeprecatedAlbumAutoFolderPathOption.hjson
similarity index 91%
rename from internal/config/testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson
rename to internal/config/testdata/valid-config/configWithDeprecatedAlbumAutoFolderPathOption.hjson
index 7524446..1005620 100644
--- a/internal/config/testdata/valid-config/configWithAlbumAutoFolderPathOption.hjson
+++ b/internal/config/testdata/valid-config/configWithDeprecatedAlbumAutoFolderPathOption.hjson
@@ -10,7 +10,7 @@
   [
     {
       SourceFolder: ./testdata/valid-config
-      Album: name:albumName
+      Album: auto:folderPath
       DeleteAfterUpload: false
       IncludePatterns: []
       ExcludePatterns: []