Repository: favonia/cloudflare-ddns
Pull request #958 (2024-09-30 13:17:43)

fix(pp): print blank lines to separate each round of updating
Partially address #954.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/958?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) Report
Attention: Patch coverage is `85.71429%` with `1 line` in your changes missing coverage. Please review.
> Project coverage is 95.82%. Comparing base [(`5b12a38`)](https://app.codecov.io/gh/favonia/cloudflare-ddns/commit/5b12a38f8dbec3f9d1dc17b00dc2b52cff1adc20?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) to head [(`4a3e0f7`)](https://app.codecov.io/gh/favonia/cloudflare-ddns/commit/4a3e0f71fa4ce5b2fd3a9987ea8269a08e3c197d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).

| [Files with missing lines](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/958?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | Patch % | Lines |
|---|---|---|
| [cmd/ddns/ddns.go](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/958?src=pr&el=tree&filepath=cmd%2Fddns%2Fddns.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia#diff-Y21kL2RkbnMvZGRucy5nbw==) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/958?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #958      +/-   ##
==========================================
- Coverage   95.84%   95.82%   -0.03%     
==========================================
  Files          62       62              
  Lines        2867     2874       +7     
==========================================
+ Hits         2748     2754       +6     
- Misses        107      108       +1     
  Partials       12       12              
```

| [Flag](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/958/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/958/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | `95.82% <85.71%> (-0.03%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/958?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).


Patch:
diff --git a/cmd/ddns/ddns.go b/cmd/ddns/ddns.go
index 79cd694..18f3d97 100644
--- a/cmd/ddns/ddns.go
+++ b/cmd/ddns/ddns.go
@@ -124,6 +124,9 @@ func realMain() int {
 		if first && !c.UpdateOnStart {
 			c.Monitor.Ping(ctx, ppfmt, monitor.NewMessagef(true, "Started (no action)"))
 		} else {
+			// Improve readability of the logging by separating each round of checks with blank lines.
+			ppfmt.BlankLineIfVerbose()
+
 			msg := updater.UpdateIPs(ctxWithSignals, ppfmt, c, s)
 			c.Monitor.Ping(ctx, ppfmt, msg.MonitorMessage)
 			c.Notifier.Send(ctx, ppfmt, msg.NotifierMessage)
diff --git a/internal/config/env_auth.go b/internal/config/env_auth.go
index b0e4e33..69a80f6 100644
--- a/internal/config/env_auth.go
+++ b/internal/config/env_auth.go
@@ -20,7 +20,7 @@ const (
 
 // HintAuthTokenNewPrefix contains the hint about the transition from
 // CF_* to CLOUDFLARE_*.
-const HintAuthTokenNewPrefix string = "Cloudflare is transitioning its tools to use the prefix CLOUDFLARE instead of CF. To align with this change, it is recommended to use CLOUDFLARE_API_TOKEN (or CLOUDFLARE_API_TOKEN_FILE) instead of CF_API_TOKEN (or CF_API_TOKEN_FILE) moving forward. All options will be fully supported until version 2.0." //nolint:lll,gosec
+const HintAuthTokenNewPrefix string = "Cloudflare is transitioning its tools to use the prefix CLOUDFLARE instead of CF. To align with this change, it is recommended to use CLOUDFLARE_API_TOKEN (or CLOUDFLARE_API_TOKEN_FILE) instead of CF_API_TOKEN (or CF_API_TOKEN_FILE) moving forward. All these options will be fully supported until version 2.0." //nolint:lll,gosec
 
 func readPlainAuthTokens(ppfmt pp.PP) (string, string, bool) {
 	token1 := Getenv(TokenKey1)
diff --git a/internal/mocks/mock_pp.go b/internal/mocks/mock_pp.go
index d7e74f6..1706ad0 100644
--- a/internal/mocks/mock_pp.go
+++ b/internal/mocks/mock_pp.go
@@ -38,6 +38,42 @@ func (m *MockPP) EXPECT() *MockPPMockRecorder {
 	return m.recorder
 }
 
+// BlankLineIfVerbose mocks base method.
+func (m *MockPP) BlankLineIfVerbose() {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "BlankLineIfVerbose")
+}
+
+// BlankLineIfVerbose indicates an expected call of BlankLineIfVerbose.
+func (mr *MockPPMockRecorder) BlankLineIfVerbose() *PPBlankLineIfVerboseCall {
+	mr.mock.ctrl.T.Helper()
+	call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlankLineIfVerbose", reflect.TypeOf((*MockPP)(nil).BlankLineIfVerbose))
+	return &PPBlankLineIfVerboseCall{Call: call}
+}
+
+// PPBlankLineIfVerboseCall wrap *gomock.Call
+type PPBlankLineIfVerboseCall struct {
+	*gomock.Call
+}
+
+// Return rewrite *gomock.Call.Return
+func (c *PPBlankLineIfVerboseCall) Return() *PPBlankLineIfVerboseCall {
+	c.Call = c.Call.Return()
+	return c
+}
+
+// Do rewrite *gomock.Call.Do
+func (c *PPBlankLineIfVerboseCall) Do(f func()) *PPBlankLineIfVerboseCall {
+	c.Call = c.Call.Do(f)
+	return c
+}
+
+// DoAndReturn rewrite *gomock.Call.DoAndReturn
+func (c *PPBlankLineIfVerboseCall) DoAndReturn(f func()) *PPBlankLineIfVerboseCall {
+	c.Call = c.Call.DoAndReturn(f)
+	return c
+}
+
 // Hintf mocks base method.
 func (m *MockPP) Hintf(arg0 pp.Hint, arg1 string, arg2 ...any) {
 	m.ctrl.T.Helper()
diff --git a/internal/pp/base.go b/internal/pp/base.go
index 8a14622..1749ca7 100644
--- a/internal/pp/base.go
+++ b/internal/pp/base.go
@@ -3,6 +3,18 @@ package pp
 
 //go:generate mockgen -typed -destination=../mocks/mock_pp.go -package=mocks . PP
 
+// Verbosity is the type of message levels.
+type Verbosity int
+
+// Pre-defined verbosity levels. A higher level means "more verbose".
+const (
+	Notice           Verbosity = iota // useful additional info
+	Info                              // important messages
+	Quiet            Verbosity = Notice
+	Verbose          Verbosity = Info
+	DefaultVerbosity Verbosity = Verbose
+)
+
 // PP is the abstraction of a pretty printer.
 type PP interface {
 	// IsShowing checks whether a message of a certain level will be printed.
@@ -11,6 +23,9 @@ type PP interface {
 	// Indent returns a new pretty-printer with more indentation.
 	Indent() PP
 
+	// BlankLineIfVerbose prints a blank line at the [Verbose] level
+	BlankLineIfVerbose()
+
 	// Infof formats and prints a message at the info level.
 	Infof(emoji Emoji, format string, args ...any)
 
diff --git a/internal/pp/fmt.go b/internal/pp/fmt.go
index ac3f9ab..188f892 100644
--- a/internal/pp/fmt.go
+++ b/internal/pp/fmt.go
@@ -14,18 +14,6 @@ type formatter struct {
 	verbosity Verbosity
 }
 
-// Verbosity is the type of message levels.
-type Verbosity int
-
-// Pre-defined verbosity levels. A higher level means "more verbose".
-const (
-	Notice           Verbosity = iota // useful additional info
-	Info                              // important messages
-	Quiet            Verbosity = Notice
-	Verbose          Verbosity = Info
-	DefaultVerbosity Verbosity = Verbose
-)
-
 // New creates a new pretty printer.
 func New(writer io.Writer, emoji bool, verbosity Verbosity) PP {
 	return formatter{
@@ -53,6 +41,13 @@ func (f formatter) Indent() PP {
 	return f
 }
 
+// BlankLineIfVerbose prints a blank line.
+func (f formatter) BlankLineIfVerbose() {
+	if f.IsShowing(Verbose) {
+		fmt.Fprintln(f.writer)
+	}
+}
+
 func (f formatter) output(v Verbosity, emoji Emoji, msg string) {
 	if !f.IsShowing(v) {
 		return
diff --git a/internal/pp/queued.go b/internal/pp/queued.go
index c80ad6c..53b0464 100644
--- a/internal/pp/queued.go
+++ b/internal/pp/queued.go
@@ -30,26 +30,37 @@ func (b QueuedPP) Indent() PP {
 	return b
 }
 
+// BlankLineIfVerbose queues a call to [PP.BlankLineIfVerbose] of the upstream.
+func (b QueuedPP) BlankLineIfVerbose() {
+	// It's important to save the current upstream because [Indent] may change it.
+	upstream := b.upstream
+	*b.queue = append(*b.queue, func() { upstream.BlankLineIfVerbose() })
+}
+
 // Infof queues a call to [PP.Infof] of the upstream.
 func (b QueuedPP) Infof(emoji Emoji, format string, args ...any) {
+	// It's important to save the current upstream because [Indent] may change it.
 	upstream := b.upstream
 	*b.queue = append(*b.queue, func() { upstream.Infof(emoji, format, args...) })
 }
 
 // Noticef queues a call to [PP.Noticef] of the upstream.
 func (b QueuedPP) Noticef(emoji Emoji, format string, args ...any) {
+	// It's important to save the current upstream because [Indent] may change it.
 	upstream := b.upstream
 	*b.queue = append(*b.queue, func() { upstream.Noticef(emoji, format, args...) })
 }
 
 // SuppressHint queues a call to [PP.SuppressHint] of the upstream.
 func (b QueuedPP) SuppressHint(hint Hint) {
+	// It's important to save the current upstream because [Indent] may change it.
 	upstream := b.upstream
 	*b.queue = append(*b.queue, func() { upstream.SuppressHint(hint) })
 }
 
 // Hintf queues a call to [PP.Hintf] of the upstream.
 func (b QueuedPP) Hintf(hint Hint, format string, args ...any) {
+	// It's important to save the current upstream because [Indent] may change it.
 	upstream := b.upstream
 	*b.queue = append(*b.queue, func() { upstream.Hintf(hint, format, args...) })
 }


Test patch:
diff --git a/internal/pp/fmt_test.go b/internal/pp/fmt_test.go
index a76762a..1d69935 100644
--- a/internal/pp/fmt_test.go
+++ b/internal/pp/fmt_test.go
@@ -42,14 +42,18 @@ func TestIndent(t *testing.T) {
 	middle.Noticef(pp.EmojiStar, "message2")
 	inner := middle.Indent()
 	outer.Noticef(pp.EmojiStar, "message3")
+	outer.BlankLineIfVerbose()
 	inner.Noticef(pp.EmojiStar, "message4")
+	inner.BlankLineIfVerbose()
 	middle.Noticef(pp.EmojiStar, "message5")
 
 	require.Equal(t,
 		`🌟 message1
    🌟 message2
 🌟 message3
+
       🌟 message4
+
    🌟 message5
 `,
 		buf.String())
diff --git a/internal/pp/queued_test.go b/internal/pp/queued_test.go
index 2dcb0e0..a32d397 100644
--- a/internal/pp/queued_test.go
+++ b/internal/pp/queued_test.go
@@ -25,6 +25,7 @@ func TestQueued(t *testing.T) {
 				}
 				ppfmt.Noticef(pp.EmojiNotify, "some message")
 				ppfmt.SuppressHint(pp.HintDetectionTimeouts)
+				ppfmt.BlankLineIfVerbose()
 				ppfmt.Hintf(pp.HintIP4DetectionFails, "cannot do IPv4")
 
 				queued.Flush()
@@ -36,6 +37,7 @@ func TestQueued(t *testing.T) {
 					ppfmt.EXPECT().Infof(pp.EmojiBullet, "Test"),
 					inner.EXPECT().Noticef(pp.EmojiNotify, "some message"),
 					inner.EXPECT().SuppressHint(pp.HintDetectionTimeouts),
+					inner.EXPECT().BlankLineIfVerbose(),
 					inner.EXPECT().Hintf(pp.HintIP4DetectionFails, "cannot do IPv4"),
 				)
 			},