-
Notifications
You must be signed in to change notification settings - Fork 320
Modernize sources, add golangci-lint #466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
7d5ea6e
to
e407489
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR modernizes the go-systemd codebase to leverage Go 1.22+ features while adding golangci-lint static analysis and code formatting. The changes focus on updating syntax, fixing linter issues, and standardizing the codebase.
- Modernizes Go syntax using newer language features (range over integers, simplified composite literals)
- Replaces deprecated
ioutil
withos
package functions and updates build constraints syntax - Adds golangci-lint configuration and GitHub Actions workflow while removing manual fmt/vet checks
Reviewed Changes
Copilot reviewed 46 out of 46 changed files in this pull request and generated 5 comments.
Show a summary per file
File | Description |
---|---|
util/*.go | Remove old build constraint syntax, replace ioutil with os.ReadFile, simplify variable declarations |
unit/*.go | Use modern range syntax, simplified composite literals, replace ioutil with io package |
sdjournal/*.go | Update package documentation, use modern syntax, improve test helpers |
dbus/*.go | Update package documentation, use modern syntax, fix variable naming |
journal/*.go | Replace ioutil with os package, update build constraints |
activation/*.go | Improve error handling in tests, use modern syntax |
.golangci.yml | Add golangci-lint configuration with minimal settings |
.github/workflows/go.yml | Replace manual fmt/vet with golangci-lint action |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
unit/deserialize.go
Outdated
} | ||
|
||
l.buf.UnreadRune() | ||
_ = l.buf.UnreadRune() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider handling the error from UnreadRune() instead of discarding it, as this could indicate a serious issue with the buffer state.
_ = l.buf.UnreadRune() | |
if err := l.buf.UnreadRune(); err != nil { | |
return nil, err | |
} |
Copilot uses AI. Check for mistakes.
case "org.freedesktop.systemd1.Manager.JobRemoved": | ||
unitName := signal.Body[2].(string) | ||
c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) | ||
_ = c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider handling the error from the D-Bus call instead of discarding it, as this could indicate communication issues with systemd.
_ = c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) | |
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) | |
if err != nil { | |
log.Printf("failed to get unit path for %s: %v", unitName, err) | |
continue | |
} |
Copilot uses AI. Check for mistakes.
*/ | ||
fmt.Fprintln(w, name) | ||
binary.Write(w, binary.LittleEndian, uint64(len(value))) | ||
_ = binary.Write(w, binary.LittleEndian, uint64(len(value))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider handling the error from binary.Write() instead of discarding it, as this could indicate issues with writing journal data.
_ = binary.Write(w, binary.LittleEndian, uint64(len(value))) | |
if err := binary.Write(w, binary.LittleEndian, uint64(len(value))); err != nil { | |
fmt.Fprintf(os.Stderr, "failed to write variable size for %s: %v\n", name, err) | |
} |
Copilot uses AI. Check for mistakes.
var result string | ||
dbus.Store(signal.Body, &id, &job, &unit, &result) | ||
|
||
_ = dbus.Store(signal.Body, &id, &job, &unit, &result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider handling the error from dbus.Store() instead of discarding it, as this could indicate malformed D-Bus signals.
_ = dbus.Store(signal.Body, &id, &job, &unit, &result) | |
if err := dbus.Store(signal.Body, &id, &job, &unit, &result); err != nil { | |
log.Printf("dbus: failed to decode signal body in jobComplete: %v", err) | |
return | |
} |
Copilot uses AI. Check for mistakes.
defer func() { | ||
_ = os.Unsetenv("LISTEN_PID") | ||
_ = os.Unsetenv("LISTEN_FDS") | ||
_ = os.Unsetenv("LISTEN_FDNAMES") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider handling the error from os.Unsetenv() instead of discarding it, as this could indicate permission issues or other environment problems.
_ = os.Unsetenv("LISTEN_FDNAMES") | |
if err := os.Unsetenv("LISTEN_PID"); err != nil { | |
log.Printf("failed to unset LISTEN_PID: %v", err) | |
} | |
if err := os.Unsetenv("LISTEN_FDS"); err != nil { | |
log.Printf("failed to unset LISTEN_FDS: %v", err) | |
} | |
if err := os.Unsetenv("LISTEN_FDNAMES"); err != nil { | |
log.Printf("failed to unset LISTEN_FDNAMES: %v", err) | |
} |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM mostly, only a few comments
unit/doc.go
Outdated
@@ -0,0 +1,26 @@ | |||
// Copyright 2015 CoreOS, Inc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should do about the copyright header?
Copyright 2015 CoreOS, Inc.
doesn't seem to make sense anymore.
Or just drop it entirely from the files? I don't think it is required, at least our other projects don't include it every file either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, as far as I know there's no requirement to have a copyright in every source file. Will remove.
// ErrLineTooLong gets returned when a line is too long for systemd to handle. | ||
var ErrLineTooLong = fmt.Errorf("line too long (max %d bytes)", SYSTEMD_LINE_MAX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind that change but it seems unrelated to this commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, it's gofumpt. Removed from this patch.
dbus/methods.go
Outdated
// No way to return an error. | ||
_ = c.KillUnitWithTarget(ctx, name, All, signal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the change but I wonder if we should mark this function as deprecated and let people use KillUnitWithTarget given this here just eats the error silently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was thinking the same thing. Amended.
unit/deserialize.go
Outdated
} | ||
|
||
l.buf.UnreadRune() | ||
_ = l.buf.UnreadRune() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be worth to a comment here saying that this should never error as we called ReadRune() before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@Luap99 addressed all your comments (and some of copilot ones). |
Since Go 1.18, any is a type alias for interface{}. Brought to you by modernize -category=efaceany -fix -test ./... Signed-off-by: Kir Kolyshkin <[email protected]>
Since Go 1.22 one can use "for i := range n" as a shortcut for "for i := 0; i < n; i++". Brought to you by modernize -category=rangeint -fix -test ./... Signed-off-by: Kir Kolyshkin <[email protected]>
Also, simplify the checking code. Signed-off-by: Kir Kolyshkin <[email protected]>
Reported by golangci-lint: login1/dbus.go:114:18: func Session.toInterface is unused (unused) func (s Session) toInterface() []any { ^ Signed-off-by: Kir Kolyshkin <[email protected]>
Reported by golangci-lint: machine1/dbus_test.go:151:2: SA1019: rand.Seed has been deprecated since Go 1.20 and an alternative has been available since Go 1.0: As of Go 1.20 there is no reason to call Seed with a random value. Programs that call Seed with a known value to get a specific sequence of results should use New(NewSource(seed)) to obtain a local random generator. (staticcheck) rand.Seed(time.Now().UnixNano()) ^ Signed-off-by: Kir Kolyshkin <[email protected]>
The io/ioutil package is deprecated since Go 1.16. This patch replaces - ioutil.TempDir -> t.TempDir (in tests) - ioutil.TempFile -> os.CreateTemp - ioutil.ReadFile -> os.ReadFile - ioutil.ReadAll -> io.ReadAll Signed-off-by: Kir Kolyshkin <[email protected]>
Fixes the following govet warning: dbus/methods_test.go:1449:26: nilness: tautological condition: non-nil != nil (govet) if tch == nil || (tch != nil && tch.Name == target && tch.ActiveState != "active") { ^ Signed-off-by: Kir Kolyshkin <[email protected]>
Signed-off-by: Kir Kolyshkin <[email protected]>
Setenv is available for tests since go 1.17. Technically, this changes the test logic a bit because instead of using Unsetenv, tests are now using Setenv with empty value. Practically, this makes no difference as the code being tested treats empty (but set) value the same way as unset. Signed-off-by: Kir Kolyshkin <[email protected]>
...instead of \"%s\". Signed-off-by: Kir Kolyshkin <[email protected]>
Let's put common testing code into functions, and also use t.Cleanup, t.Helper, and t.Fatalf instead of returning an error. This makes the code smaller, and (indirectly) fixes a bunch of linter warnings like these: sdjournal/journal_test.go:225:60: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors (errorlint) return nil, nil, fmt.Errorf("Error opening journal: %s", err) ^ sdjournal/journal_test.go:157:15: Error return value of `j.Close` is not checked (errcheck) defer j.Close() ^ sdjournal/journal_test.go:165:3: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck) t.Fatalf(err.Error()) ^ Signed-off-by: Kir Kolyshkin <[email protected]>
Like this: dbus/subscription_test.go:104:2: SA5001: should check error returned from New() before deferring conn.Close() (staticcheck) defer conn.Close() ^ Signed-off-by: Kir Kolyshkin <[email protected]>
Like this one: activation/files_test.go:56:3: SA1006: printf-style function with dynamic format string and no further arguments should use print-style function instead (staticcheck) t.Fatalf(err.Error()) ^ Signed-off-by: Kir Kolyshkin <[email protected]>
1. Use io.Reader to generalise connectStringWritten and drop connectStringWrittenNet. 2. Don't return anything as the return value is never used. 3. Use t.Helper. Signed-off-by: Kir Kolyshkin <[email protected]>
unit/deserialize.go:96:31: SA4001: &*x will be simplified to x. It will not copy x. (staticcheck) options = append(options, &(*opt)) ^ Signed-off-by: Kir Kolyshkin <[email protected]>
Signed-off-by: Kir Kolyshkin <[email protected]>
dbus/methods.go:871:16: ST1016: methods on the same type should have the same receiver name (seen 1x "conn", 92x "c") (staticcheck) Signed-off-by: Kir Kolyshkin <[email protected]>
Co-authored-by: Claude Code Signed-off-by: Kir Kolyshkin <[email protected]>
Fix the following warning: SA4004: the surrounding loop is unconditionally terminated Indeed, the for loop here only iterates once, and thus the code is slightly hard to read. Reimplement the same logic without using loop. While at it, simplify the check for \\ at EOL by using bytes.HasSuffix. Co-authored-by: Claude Code Signed-off-by: Kir Kolyshkin <[email protected]>
sdjournal/journal_test.go:350:34: SA1024: cutset contains duplicate characters (staticcheck) if got[1] != strings.Trim(want, delim) { ^ Signed-off-by: Kir Kolyshkin <[email protected]>
This fixes the following staticcheck warning: journal/journal_unix.go:216:6: QF1001: could apply De Morgan's law (staticcheck) if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') { ^ Signed-off-by: Kir Kolyshkin <[email protected]>
Indeed, we should not use/test deprecated methods. This fixes the following warnings: machine1/dbus_test.go:51:19: SA1019: sd_dbus.New is deprecated: use NewWithContext instead. (staticcheck) dbusConn, err := sd_dbus.New() ^ machine1/dbus_test.go:56:26: SA1019: dbusConn.GetServiceProperty is deprecated: use GetServicePropertyContext instead. (staticcheck) mainPIDProperty, err := dbusConn.GetServiceProperty(testServiceName, "MainPID") ^ Signed-off-by: Kir Kolyshkin <[email protected]>
This one: activation/files_unix.go:42:20: Error return value of `os.Unsetenv` is not checked (errcheck) Since - current unix implementation of os.Unsetenv never returns an error; - there is no way to return an error; let's just ignore it. Signed-off-by: Kir Kolyshkin <[email protected]>
There is no way to return an error from KillUnitContext, and we already have KillUnitWithTarget which returns an error. - explicitly ignore the error in KillUnitContext; - deprecate KillUnitContext in favor of KillUnitWithTarget; - fix the KillUnit deprecation warning to point to KillUnitWithTarget; - improve KillUnitWithTarget and Who docs. Signed-off-by: Kir Kolyshkin <[email protected]>
Ignore a few warnings like this: Error return value of `xxx` is not checked (errcheck) In all cases either there's no way to return an error, or (it seems) the code is working on a "best effort" basis. Signed-off-by: Kir Kolyshkin <[email protected]>
Signed-off-by: Kir Kolyshkin <[email protected]>
Add a helper to run sleep process with a proper cleanup, so we don't forget to call wait on a process we ran, and check for any errors. Signed-off-by: Kir Kolyshkin <[email protected]>
Signed-off-by: Kir Kolyshkin <[email protected]>
1. Make use of t which was unused before. 2. Ignore stopUnit return value. 3. Check os.Remove return value (which can fail the test early). Signed-off-by: Kir Kolyshkin <[email protected]>
Signed-off-by: Kir Kolyshkin <[email protected]>
Gofumpt is a superset of gofmt, enabling some extra rules resulting, for the most part, in a more readable code. This replaces gofmt (which will be removed in the next commit). Signed-off-by: Kir Kolyshkin <[email protected]>
Brought to you by go fix ./... Signed-off-by: Kir Kolyshkin <[email protected]>
This also removes go vet and gofmt, as those are built into golangci-lint. Signed-off-by: Kir Kolyshkin <[email protected]>
Signed-off-by: Kir Kolyshkin <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This can be split into a few major blocks:
gofmt
/go vet
).I tried hard to minimize the changes and be conservative, but might have failed in a few places.