From d7222c7d386b9502d8c93cc6a0c8094d928cbae9 Mon Sep 17 00:00:00 2001
From: Viktoras Makauskas <viktoras@neglostyti.com>
Date: Fri, 10 Apr 2020 23:46:19 +0300
Subject: [PATCH 1/7] Adding github actions output format

---
 pkg/commands/run.go         |  2 ++
 pkg/config/config.go        |  2 ++
 pkg/printers/github.go      | 38 +++++++++++++++++++++++++++++++++++++
 pkg/printers/github_test.go | 25 ++++++++++++++++++++++++
 4 files changed, 67 insertions(+)
 create mode 100644 pkg/printers/github.go
 create mode 100644 pkg/printers/github_test.go

diff --git a/pkg/commands/run.go b/pkg/commands/run.go
index b306802a..b805995e 100644
--- a/pkg/commands/run.go
+++ b/pkg/commands/run.go
@@ -396,6 +396,8 @@ func (e *Executor) createPrinter() (printers.Printer, error) {
 		p = printers.NewCodeClimate()
 	case config.OutFormatJunitXML:
 		p = printers.NewJunitXML()
+	case config.OutFormatGithubActions:
+		p = printers.NewGithub()
 	default:
 		return nil, fmt.Errorf("unknown output format %s", format)
 	}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index a4c7e453..f68925c7 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -15,6 +15,7 @@ const (
 	OutFormatCheckstyle        = "checkstyle"
 	OutFormatCodeClimate       = "code-climate"
 	OutFormatJunitXML          = "junit-xml"
+	OutFormatGithubActions     = "github-actions"
 )
 
 var OutFormats = []string{
@@ -25,6 +26,7 @@ var OutFormats = []string{
 	OutFormatCheckstyle,
 	OutFormatCodeClimate,
 	OutFormatJunitXML,
+	OutFormatGithubActions,
 }
 
 type ExcludePattern struct {
diff --git a/pkg/printers/github.go b/pkg/printers/github.go
new file mode 100644
index 00000000..c8205f45
--- /dev/null
+++ b/pkg/printers/github.go
@@ -0,0 +1,38 @@
+package printers
+
+import (
+	"context"
+	"fmt"
+	"github.com/golangci/golangci-lint/pkg/logutils"
+	"github.com/golangci/golangci-lint/pkg/result"
+)
+
+type github struct {
+}
+
+// Github output format outputs issues according to Github actions format:
+// https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
+func NewGithub() Printer {
+	return &github{}
+}
+
+// print each line as: ::error file=app.js,line=10,col=15::Something went wrong
+func formatIssueAsGithub(issue result.Issue) string {
+	result := fmt.Sprintf("::error file=%s,line=%d", issue.FilePath(), issue.Line())
+	if issue.Pos.Column != 0 {
+		result += fmt.Sprintf(",col=%d", issue.Pos.Column)
+	}
+
+	result += fmt.Sprintf("::%s (%s)", issue.Text, issue.FromLinter)
+	return result
+}
+
+func (g *github) Print(ctx context.Context, issues []result.Issue) error {
+	for _, issue := range issues {
+		_, err := fmt.Fprintln(logutils.StdOut, formatIssueAsGithub(issue))
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/pkg/printers/github_test.go b/pkg/printers/github_test.go
new file mode 100644
index 00000000..5fee530d
--- /dev/null
+++ b/pkg/printers/github_test.go
@@ -0,0 +1,25 @@
+package printers
+
+import (
+	"github.com/golangci/golangci-lint/pkg/result"
+	"github.com/stretchr/testify/require"
+	"go/token"
+	"testing"
+)
+
+func TestFormatGithubIssue(t *testing.T) {
+	sampleIssue := result.Issue{
+		FromLinter: "sample-linter",
+		Text:       "some issue",
+		Pos: token.Position{
+			Filename: "path/to/file.go",
+			Offset:   2,
+			Line:     10,
+			Column:   4,
+		},
+	}
+	require.Equal(t, "::error file=path/to/file.go,line=10,col=4::some issue (sample-linter)", formatIssueAsGithub(sampleIssue))
+
+	sampleIssue.Pos.Column = 0
+	require.Equal(t, "::error file=path/to/file.go,line=10::some issue (sample-linter)", formatIssueAsGithub(sampleIssue))
+}

From ee2c62132cd675df37d32ec7b21e69d6b92fc59c Mon Sep 17 00:00:00 2001
From: Viktoras Makauskas <viktoras@neglostyti.com>
Date: Fri, 10 Apr 2020 23:59:07 +0300
Subject: [PATCH 2/7] Fixing linter issues

---
 pkg/printers/github.go      | 13 +++++++------
 pkg/printers/github_test.go | 10 ++++++----
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/pkg/printers/github.go b/pkg/printers/github.go
index c8205f45..41934be0 100644
--- a/pkg/printers/github.go
+++ b/pkg/printers/github.go
@@ -3,6 +3,7 @@ package printers
 import (
 	"context"
 	"fmt"
+
 	"github.com/golangci/golangci-lint/pkg/logutils"
 	"github.com/golangci/golangci-lint/pkg/result"
 )
@@ -17,19 +18,19 @@ func NewGithub() Printer {
 }
 
 // print each line as: ::error file=app.js,line=10,col=15::Something went wrong
-func formatIssueAsGithub(issue result.Issue) string {
-	result := fmt.Sprintf("::error file=%s,line=%d", issue.FilePath(), issue.Line())
+func formatIssueAsGithub(issue *result.Issue) string {
+	ret := fmt.Sprintf("::error file=%s,line=%d", issue.FilePath(), issue.Line())
 	if issue.Pos.Column != 0 {
-		result += fmt.Sprintf(",col=%d", issue.Pos.Column)
+		ret += fmt.Sprintf(",col=%d", issue.Pos.Column)
 	}
 
-	result += fmt.Sprintf("::%s (%s)", issue.Text, issue.FromLinter)
-	return result
+	ret += fmt.Sprintf("::%s (%s)", issue.Text, issue.FromLinter)
+	return ret
 }
 
 func (g *github) Print(ctx context.Context, issues []result.Issue) error {
 	for _, issue := range issues {
-		_, err := fmt.Fprintln(logutils.StdOut, formatIssueAsGithub(issue))
+		_, err := fmt.Fprintln(logutils.StdOut, formatIssueAsGithub(&issue))
 		if err != nil {
 			return err
 		}
diff --git a/pkg/printers/github_test.go b/pkg/printers/github_test.go
index 5fee530d..0ab79bb8 100644
--- a/pkg/printers/github_test.go
+++ b/pkg/printers/github_test.go
@@ -1,10 +1,12 @@
 package printers
 
 import (
-	"github.com/golangci/golangci-lint/pkg/result"
-	"github.com/stretchr/testify/require"
 	"go/token"
 	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"github.com/golangci/golangci-lint/pkg/result"
 )
 
 func TestFormatGithubIssue(t *testing.T) {
@@ -18,8 +20,8 @@ func TestFormatGithubIssue(t *testing.T) {
 			Column:   4,
 		},
 	}
-	require.Equal(t, "::error file=path/to/file.go,line=10,col=4::some issue (sample-linter)", formatIssueAsGithub(sampleIssue))
+	require.Equal(t, "::error file=path/to/file.go,line=10,col=4::some issue (sample-linter)", formatIssueAsGithub(&sampleIssue))
 
 	sampleIssue.Pos.Column = 0
-	require.Equal(t, "::error file=path/to/file.go,line=10::some issue (sample-linter)", formatIssueAsGithub(sampleIssue))
+	require.Equal(t, "::error file=path/to/file.go,line=10::some issue (sample-linter)", formatIssueAsGithub(&sampleIssue))
 }

From da4a14d8277e84e5a89a87254c00b136a6bf8b3e Mon Sep 17 00:00:00 2001
From: Viktoras <viktoras@neglostyti.com>
Date: Sat, 11 Apr 2020 00:02:35 +0300
Subject: [PATCH 3/7] Update pkg/printers/github.go

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>
---
 pkg/printers/github.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pkg/printers/github.go b/pkg/printers/github.go
index 41934be0..5374a2ec 100644
--- a/pkg/printers/github.go
+++ b/pkg/printers/github.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 
+
 	"github.com/golangci/golangci-lint/pkg/logutils"
 	"github.com/golangci/golangci-lint/pkg/result"
 )

From 276e0d1e3bd01b70bb116758475919ff895168bb Mon Sep 17 00:00:00 2001
From: Viktoras Makauskas <viktoras@neglostyti.com>
Date: Sat, 11 Apr 2020 00:11:14 +0300
Subject: [PATCH 4/7] Fixing linter issues

---
 pkg/printers/github.go | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/pkg/printers/github.go b/pkg/printers/github.go
index 5374a2ec..b170f8c9 100644
--- a/pkg/printers/github.go
+++ b/pkg/printers/github.go
@@ -30,8 +30,9 @@ func formatIssueAsGithub(issue *result.Issue) string {
 }
 
 func (g *github) Print(ctx context.Context, issues []result.Issue) error {
-	for _, issue := range issues {
-		_, err := fmt.Fprintln(logutils.StdOut, formatIssueAsGithub(&issue))
+	for ind := range issues {
+		issue := &issues[ind]
+		_, err := fmt.Fprintln(logutils.StdOut, formatIssueAsGithub(issue))
 		if err != nil {
 			return err
 		}

From 69a4e811d7ffc825406b5259bd998c3af73d3846 Mon Sep 17 00:00:00 2001
From: Viktoras <viktoras@neglostyti.com>
Date: Sat, 11 Apr 2020 00:12:29 +0300
Subject: [PATCH 5/7] Update pkg/printers/github.go

Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com>
---
 pkg/printers/github.go | 1 -
 1 file changed, 1 deletion(-)

diff --git a/pkg/printers/github.go b/pkg/printers/github.go
index b170f8c9..ee2c46fc 100644
--- a/pkg/printers/github.go
+++ b/pkg/printers/github.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"fmt"
 
-
 	"github.com/golangci/golangci-lint/pkg/logutils"
 	"github.com/golangci/golangci-lint/pkg/result"
 )

From 04e6fd5d755badd7b5ffb7595d36e570b301adcb Mon Sep 17 00:00:00 2001
From: Viktoras Makauskas <viktoras@neglostyti.com>
Date: Sat, 11 Apr 2020 00:24:26 +0300
Subject: [PATCH 6/7] update README.md

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 9a86b13f..278f35cd 100644
--- a/README.md
+++ b/README.md
@@ -509,7 +509,7 @@ Usage:
   golangci-lint run [flags]
 
 Flags:
-      --out-format string              Format of output: colored-line-number|line-number|json|tab|checkstyle|code-climate|junit-xml (default "colored-line-number")
+      --out-format string              Format of output: colored-line-number|line-number|json|tab|checkstyle|code-climate|junit-xml|github-actions (default "colored-line-number")
       --print-issued-lines             Print lines of code with issue (default true)
       --print-linter-name              Print linter name in issue line (default true)
       --uniq-by-line                   Make issues output unique by line (default true)

From b7dada224923926e8f325fc1f6fcbce62633841d Mon Sep 17 00:00:00 2001
From: Viktoras Makauskas <viktoras@neglostyti.com>
Date: Sat, 11 Apr 2020 00:41:24 +0300
Subject: [PATCH 7/7] slight cleanup

---
 pkg/printers/github.go | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/pkg/printers/github.go b/pkg/printers/github.go
index ee2c46fc..fa11a283 100644
--- a/pkg/printers/github.go
+++ b/pkg/printers/github.go
@@ -28,10 +28,9 @@ func formatIssueAsGithub(issue *result.Issue) string {
 	return ret
 }
 
-func (g *github) Print(ctx context.Context, issues []result.Issue) error {
+func (g *github) Print(_ context.Context, issues []result.Issue) error {
 	for ind := range issues {
-		issue := &issues[ind]
-		_, err := fmt.Fprintln(logutils.StdOut, formatIssueAsGithub(issue))
+		_, err := fmt.Fprintln(logutils.StdOut, formatIssueAsGithub(&issues[ind]))
 		if err != nil {
 			return err
 		}