forked from kubernetes-sigs/cluster-api
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds in a release notes composer that's based on controller-runtime's `hack/release/` tooling & the subsequent cluster-api release tooling written by vincepri, whence it draws pretty heavily.
- Loading branch information
1 parent
4125276
commit 39377a5
Showing
12 changed files
with
2,350 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
Copyright 2020 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package common_test | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/ginkgo/extensions/table" | ||
. "github.com/onsi/gomega" | ||
|
||
. "sigs.k8s.io/kubebuilder-release-tools/notes/common" | ||
) | ||
|
||
func TestCommon(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "Common Release Not Parsing Suite") | ||
} | ||
|
||
var _ = Describe("PR title parsing", func() { | ||
DescribeTable("prefix to type", | ||
func(title string, expectedType PRType, expectedTitle string) { | ||
prType, finalTitle := PRTypeFromTitle(title) | ||
Expect(prType).To(Equal(expectedType)) | ||
Expect(finalTitle).To(Equal(expectedTitle)) | ||
}, | ||
Entry("should match breaking from ⚠", "⚠ Change leaderlock from ConfigMap to ConfigMapsLeasesResourceLock", BreakingPR, "Change leaderlock from ConfigMap to ConfigMapsLeasesResourceLock"), | ||
Entry("should match breaking from :warning:", ":warning: admission responses with raw Status", BreakingPR, "admission responses with raw Status"), | ||
Entry("should match feature from ✨", "✨CreateOrPatch", FeaturePR, "CreateOrPatch"), | ||
Entry("should match feature from :sparkles:", ":sparkles: Add error check for multiple apiTypes as reconciliation object", FeaturePR, "Add error check for multiple apiTypes as reconciliation object"), | ||
Entry("should match bugfix from 🐛", "🐛 Controller.Watch() should not store watches if already started", BugfixPR, "Controller.Watch() should not store watches if already started"), | ||
Entry("should match bugfix from :bug:", ":bug: Ensure that webhook server is thread/start-safe", BugfixPR, "Ensure that webhook server is thread/start-safe"), | ||
Entry("should match docs from 📖", "📖 Nit: improve doc string", DocsPR, "Nit: improve doc string"), | ||
Entry("should match docs from :book:", ":book: Fix typo", DocsPR, "Fix typo"), | ||
Entry("should match infra from 🌱", "🌱 some infra stuff (couldn't find in log)", InfraPR, "some infra stuff (couldn't find in log)"), | ||
Entry("should match infra from :seedling:", ":seedling: Update Go mod version to 1.15", InfraPR, "Update Go mod version to 1.15"), | ||
Entry("should match infra from 🏃(deprecated)", "🏃 hack/setup-envtest.sh: follow-up from #1092", InfraPR, "hack/setup-envtest.sh: follow-up from #1092"), | ||
Entry("should match infra from :running: (deprecated)", ":running: Proposal to extract cluster-specifics out of the Manager", InfraPR, "Proposal to extract cluster-specifics out of the Manager"), | ||
Entry("should put anything else as uncategorized", "blah blah", UncategorizedPR, "blah blah"), | ||
) | ||
|
||
It("should strip space from the start and end of the final title", func() { | ||
prType, title := PRTypeFromTitle(":sparkles: this is a feature") | ||
Expect(title).To(Equal("this is a feature")) | ||
Expect(prType).To(Equal(FeaturePR)) | ||
}) | ||
|
||
It("should strip space before considering the prefix", func() { | ||
prType, title := PRTypeFromTitle(" :sparkles:this is a feature") | ||
Expect(title).To(Equal("this is a feature")) | ||
Expect(prType).To(Equal(FeaturePR)) | ||
}) | ||
|
||
It("should strip variation selectors from the start of the final title", func() { | ||
prType, title := PRTypeFromTitle("✨\uFE0FTruly sparkly") | ||
Expect(prType).To(Equal(FeaturePR)) | ||
Expect(title).To(Equal("Truly sparkly")) | ||
}) | ||
|
||
It("should ingore emoji in the middle of the message", func() { | ||
prType, title := PRTypeFromTitle("this is not a ✨ feature") | ||
Expect(title).To(Equal("this is not a ✨ feature")) | ||
Expect(prType).To(Equal(UncategorizedPR)) | ||
}) | ||
|
||
It("should ignore github text->emoji in the middle of the message", func() { | ||
prType, title := PRTypeFromTitle("this is not a :sparkles: feature") | ||
Expect(title).To(Equal("this is not a :sparkles: feature")) | ||
Expect(prType).To(Equal(UncategorizedPR)) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
Copyright 2020 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package common | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os/exec" | ||
) | ||
|
||
// ErrOut wraps exec.ExitErrors so that the message displays their | ||
// stderr output. If the error is not an exist error, or does not | ||
// wrap one, this returns the error without any changes. | ||
func ErrOut(err error) error { | ||
var exitErr *exec.ExitError | ||
if !errors.As(err, &exitErr) { | ||
return err | ||
} | ||
return errOut{actual: exitErr} | ||
} | ||
|
||
// errOut is an Error that prints the underlying ExitError's stderr in addition | ||
// to the normal message. | ||
type errOut struct { | ||
actual *exec.ExitError | ||
} | ||
|
||
func (e errOut) Error() string { | ||
return fmt.Sprintf("[%v] %q", e.actual.Error(), string(e.actual.Stderr)) | ||
} | ||
|
||
func (e errOut) Unwrap() error { | ||
return e.actual | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
Copyright 2020 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package common | ||
|
||
import ( | ||
"strings" | ||
) | ||
|
||
type PRType int | ||
|
||
const ( | ||
UncategorizedPR PRType = iota | ||
BreakingPR | ||
FeaturePR | ||
BugfixPR | ||
DocsPR | ||
InfraPR | ||
) | ||
|
||
// NB(directxman12): These are constants because some folks' dev environments like | ||
// to inject extra combining characters into the mix (generally variation selector 16, | ||
// which indicates emoji presentation), so we want to check that these are *just* the | ||
// character without the combining parts. Note that they're a rune, so that they | ||
// can *only* be one codepoint. | ||
const ( | ||
emojiFeature = string('✨') | ||
emojiBugfix = string('🐛') | ||
emojiDocs = string('📖') | ||
emojiInfra = string('🌱') | ||
emojiBreaking = string('⚠') | ||
emojiInfraLegacy = string('🏃') | ||
) | ||
|
||
func PRTypeFromTitle(title string) (PRType, string) { | ||
title = strings.TrimSpace(title) | ||
|
||
if len(title) == 0 { | ||
return UncategorizedPR, title | ||
} | ||
|
||
var prType PRType | ||
switch { | ||
case strings.HasPrefix(title, ":sparkles:"), strings.HasPrefix(title, emojiFeature): | ||
title = strings.TrimPrefix(title, ":sparkles:") | ||
title = strings.TrimPrefix(title, emojiFeature) | ||
prType = FeaturePR | ||
case strings.HasPrefix(title, ":bug:"), strings.HasPrefix(title, emojiBugfix): | ||
title = strings.TrimPrefix(title, ":bug:") | ||
title = strings.TrimPrefix(title, emojiBugfix) | ||
prType = BugfixPR | ||
case strings.HasPrefix(title, ":book:"), strings.HasPrefix(title, emojiDocs): | ||
title = strings.TrimPrefix(title, ":book:") | ||
title = strings.TrimPrefix(title, emojiDocs) | ||
prType = DocsPR | ||
case strings.HasPrefix(title, ":seedling:"), strings.HasPrefix(title, emojiInfra): | ||
title = strings.TrimPrefix(title, ":seedling:") | ||
title = strings.TrimPrefix(title, emojiInfra) | ||
prType = InfraPR | ||
case strings.HasPrefix(title, ":warning:"), strings.HasPrefix(title, emojiBreaking): | ||
title = strings.TrimPrefix(title, ":warning:") | ||
title = strings.TrimPrefix(title, emojiBreaking) | ||
prType = BreakingPR | ||
case strings.HasPrefix(title, ":running:"), strings.HasPrefix(title, emojiInfraLegacy): | ||
// This has been deprecated in favor of :seedling: | ||
title = strings.TrimPrefix(title, ":running:") | ||
title = strings.TrimPrefix(title, emojiInfraLegacy) | ||
prType = InfraPR | ||
default: | ||
return UncategorizedPR, title | ||
} | ||
|
||
// strip the variation selector from the title, if present | ||
// (some systems sneak it in -- my guess is OSX) | ||
title = strings.TrimPrefix(title, "\uFE0F") | ||
|
||
// NB(directxman12): there are a few other cases like the variation selector, | ||
// but I can't seem to dig them up. If something doesn't parse as expected, | ||
// check for zero-width characters and add handling here. | ||
|
||
return prType, strings.TrimSpace(title) | ||
} |
Oops, something went wrong.