Skip to content

Commit

Permalink
Merge branch 'main' into collector_wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Sploder12 committed Jan 16, 2025
2 parents ed7579d + 12c4732 commit 1978bf8
Show file tree
Hide file tree
Showing 26 changed files with 1,494 additions and 43 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.go text eol=lf
45 changes: 45 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
version: 2
updates:
# Infrastructure
## GitHub Actions
- package-ecosystem: "github-actions"
# Workflow files stored in the
# default location of `.github/workflows`
directory: "/"
schedule:
interval: "weekly"
day: "thursday"
time: "09:00"
groups:
gh-actions:
#applies-to: version-updates
patterns: ["*"]
commit-message:
prefix: "deps(ci)"

## Go dependencies
- package-ecosystem: "gomod"
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
day: "thursday"
time: "09:00"
groups:
minor-updates:
#applies-to: version-updates
update-types: ["minor", "patch"]
commit-message:
prefix: "deps(go)"

- package-ecosystem: "gomod"
directory: "/tools"
schedule:
interval: "weekly"
day: "thursday"
time: "09:00"
groups:
minor-updates:
#applies-to: version-updates
update-types: ["minor", "patch"]
commit-message:
prefix: "deps(go-tools)"
12 changes: 12 additions & 0 deletions .github/workflows/git.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Git Checks

on: [pull_request]

jobs:
block-fixup:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Block Fixup Commit Merge
uses: 13rac1/[email protected]
94 changes: 94 additions & 0 deletions .github/workflows/qa.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: QA & sanity checks
on:
push:
branches:
- main
tags:
- "*"
pull_request:

env:
DEBIAN_FRONTEND: noninteractive
GO_TESTS_TIMEOUT: 20m

jobs:
go-sanity:
name: "Go: Code sanity"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, windows-2022, macos-13, macos-14] # Run on Ubuntu, Windows, Mac Intel, Mac ARM
steps:
- name: Install dependencies on Linux
if: runner.os == 'Linux'
run: |
sudo apt update
sudo apt install -y ${{ env.apt_deps }}
- uses: actions/checkout@v4
- name: Go code sanity check
uses: canonical/desktop-engineering/gh-actions/go/code-sanity@main
with:
golangci-lint-configfile: ".golangci.yaml"
tools-directory: "tools"
go-tests:
name: "Go: Tests"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
test: ["coverage", "race"]
os: [ubuntu-24.04, windows-2022, macos-13, macos-14] # Run on Ubuntu, Windows, Mac Intel, Mac ARM
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Install gotestfmt and our wrapper script
uses: canonical/desktop-engineering/gh-actions/go/gotestfmt@main

- name: Prepare tests artifacts path
run: |
set -euo pipefail
artifacts_dir=$(mktemp -d -t insights-test-artifacts-XXXXXX)
echo INSIGHTS_TEST_ARTIFACTS_PATH="${artifacts_dir}" >> $GITHUB_ENV
shell: bash

- name: Run tests (with coverage collection)
if: matrix.test == 'coverage'
env:
G_DEBUG: "fatal-criticals"
run: |
set -euo pipefail
cov_dir=$(pwd)/coverage
mkdir -p ${cov_dir}/codecov ${cov_dir}/raw
go test -shuffle=on -coverpkg=./... -coverprofile=${cov_dir}/raw/coverage.out -covermode=count ./... -tags=gowslmock
grep -hv -e "testutils" -e "pb.go:" ${cov_dir}/raw/coverage.out > ${cov_dir}/codecov/coverage.out.codecov
shell: bash

- name: Run tests (with race detector)
if: matrix.test == 'race'
env:
GO_TESTS_TIMEOUT: 35m
run: |
set -euo pipefail
go test -json -timeout ${GO_TESTS_TIMEOUT} -race ./... | \
gotestfmt --logfile "${INSIGHTS_TEST_ARTIFACTS_PATH}/gotestfmt.race.log"
shell: bash

- name: Upload coverage to Codecov
if: matrix.test == 'coverage'
uses: codecov/codecov-action@v5
with:
directory: ./coverage/codecov
token: ${{ secrets.CODECOV_TOKEN }}

- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: insights-${{ github.job }}-${{ matrix.test }}-${{ matrix.os }}-artifacts-${{ github.run_attempt }}
path: ${{ env.INSIGHTS_TEST_ARTIFACTS_PATH }}
72 changes: 72 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# This is for linting. To run it, please use:
# golangci-lint run ${MODULE}/... [--fix]

linters:
# linters to run in addition to default ones
enable:
- copyloopvar
- dupl
- dupword
- durationcheck
- errname
- errorlint
- forbidigo
- forcetypeassert
- gci
- gocheckcompilerdirectives
- godot
- gofmt
- gosec
- intrange
- misspell
- nakedret
- nolintlint
- revive
- sloglint
- testifylint
- thelper
- tparallel
- unconvert
- unparam
- usestdlibvars
- whitespace

run:
timeout: 5m

# Get all linter issues, even if duplicated
issues:
exclude-use-default: false
max-issues-per-linter: 0
max-same-issues: 0
fix: false # we don’t want this in CI
exclude:
# EXC0001 errcheck: most errors are in defer calls, which are safe to ignore and idiomatic Go (would be good to only ignore defer ones though)
- 'Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv|w\.Stop). is not checked'
# EXC0008 gosec: duplicated of errcheck
- (G104|G307)
# EXC0010 gosec: False positive is triggered by 'src, err := ioutil.ReadFile(filename)'
- Potential file inclusion via variable
# We don't wrap errors on purpose
- non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
# We want named parameters even if unused, as they help better document the function
- unused-parameter
# Sometimes it is more readable it do a `if err:=a(); err != nil` tha simpy `return a()`
- if-return
# Outdated warining, it only applies to Go < 1.22
# G601: Implicit memory aliasing in for loop.
- G601

nolintlint:
require-explanation: true
require-specific: true

linters-settings:
# Forbid the usage of deprecated ioutil and debug prints
forbidigo:
forbid:
- ioutil\.
- ^print.*$
# Never have naked return ever
nakedret:
max-func-lines: 1
1 change: 1 addition & 0 deletions cmd/exposed-server/daemon/daemon.go
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
// Package daemon is responsible for running the exposed-server in the background.
package daemon
5 changes: 5 additions & 0 deletions cmd/exposed-server/main.go
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
// Package main for the exposed-server.
package main

func main() {

}
1 change: 1 addition & 0 deletions cmd/ingest-server/daemon/daemon.go
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
// Package daemon is responsible for running the ingest-server in the background.
package daemon
5 changes: 5 additions & 0 deletions cmd/ingest-server/main.go
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
// Package main for the ingest-server.
package main

func main() {

}
9 changes: 4 additions & 5 deletions cmd/insights/commands/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var defaultCollectConfig = collectConfig{
extraMetrics: "",
}

func installCollectCmd(app *App) error {
func installCollectCmd(app *App) {
app.collectConfig = defaultCollectConfig

collectCmd := &cobra.Command{
Expand All @@ -40,16 +40,16 @@ func installCollectCmd(app *App) error {

if len(args) != 0 {
if err := cobra.MatchAll(cobra.OnlyValidArgs, cobra.ExactArgs(2))(cmd, args); err != nil {
return fmt.Errorf("accepts no args, or exactly 2 args, recieved 1")
return fmt.Errorf("accepts no args, or exactly 2 args, received 1")
}

fileInfo, err := os.Stat(args[1])
if err != nil {
return fmt.Errorf("the second argument, SOURCE-METRICS-PATH, should be a valid JSON file. Error: %s", err.Error())
return fmt.Errorf("the second argument, source-metrics-path, should be a valid JSON file. Error: %s", err.Error())
}

if fileInfo.IsDir() {
return fmt.Errorf("the second argument, SOURCE-METRICS-PATH, should be a valid JSON file, not a directory.")
return fmt.Errorf("the second argument, source-metrics-path, should be a valid JSON file, not a directory")
}
}

Expand All @@ -73,5 +73,4 @@ func installCollectCmd(app *App) error {
collectCmd.Flags().BoolVarP(&app.collectConfig.dryRun, "dry-run", "d", false, "perform a dry-run where a report is collected, but not written to disk")

app.rootCmd.AddCommand(collectCmd)
return nil
}
13 changes: 13 additions & 0 deletions cmd/insights/commands/consent.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package commands

import (
"fmt"
"log/slog"
"slices"
"strings"

"github.com/spf13/cobra"
Expand All @@ -25,6 +27,17 @@ func installConsentCmd(app *App) {
Short: "Manage or get user consent state",
Long: "Manage or get user consent state for data collection and upload",
Args: cobra.ArbitraryArgs,
PreRunE: func(cmd *cobra.Command, args []string) error {
app.rootCmd.SilenceUsage = false

validConsentStates := []string{"true", "false", ""}
if !slices.Contains(validConsentStates, strings.ToLower(app.consentConfig.consentState)) {
return fmt.Errorf("consent-state must be either true, false, or not set")
}

app.rootCmd.SilenceUsage = true
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
// Set Sources to Args
app.consentConfig.sources = args
Expand Down
10 changes: 5 additions & 5 deletions cmd/insights/commands/root.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package commands contains the commands for the Ubuntu Insights CLI.
package commands

import (
Expand All @@ -7,8 +8,7 @@ import (
"github.com/ubuntu/ubuntu-insights/internal/constants"
)

const cmdName = "ubuntu-insights"

// App represents the application.
type App struct {
rootCmd *cobra.Command

Expand All @@ -30,11 +30,11 @@ var defaultRootConfig = rootConfig{
InsightsDir: constants.GetDefaultCachePath(),
}

// Registers commands and returns a new app
// New registers commands and returns a new App.
func New() (*App, error) {
a := App{}
a.rootCmd = &cobra.Command{
Use: "ubuntu-insights [COMMAND]",
Use: constants.CmdName + " [COMMAND]",
Short: "",
Long: "",
SilenceErrors: true,
Expand All @@ -48,7 +48,7 @@ func New() (*App, error) {
}

err := installRootCmd(&a)
err = installCollectCmd(&a)
installCollectCmd(&a)
installUploadCmd(&a)
installConsentCmd(&a)

Expand Down
6 changes: 3 additions & 3 deletions cmd/insights/commands/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package commands

import (
"context"
"testing"

"log/slog"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ubuntu/ubuntu-insights/internal/constants"
)

Expand Down Expand Up @@ -50,7 +50,7 @@ func TestSetVerbosity(t *testing.T) {

func TestUsageError(t *testing.T) {
app, err := New()
assert.NoError(t, err)
require.NoError(t, err)

// Test when SilenceUsage is true
app.rootCmd.SilenceUsage = true
Expand Down
2 changes: 1 addition & 1 deletion cmd/insights/commands/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func installUploadCmd(app *App) {
app.uploadConfig = defaultUploadConfig

uploadCmd := &cobra.Command{
Use: "upload upload [sources](optional arguments)",
Use: "upload [sources](optional arguments)",
Short: "Upload metrics to the Ubuntu Insights server",
Long: "Upload metrics to the Ubuntu Insights server",
Args: cobra.ArbitraryArgs,
Expand Down
4 changes: 2 additions & 2 deletions cmd/insights/main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Main package for the insights command line tool.
package main

import (
"os"

"log/slog"
"os"

"github.com/ubuntu/ubuntu-insights/cmd/insights/commands"
"github.com/ubuntu/ubuntu-insights/internal/constants"
Expand Down
Loading

0 comments on commit 1978bf8

Please sign in to comment.