Skip to content

Commit a3dc82d

Browse files
Merge pull request #3 from cloudfoundry-community/norm/add-extended-build-info
Norm/add extended build info
2 parents dc89d19 + d9ecc50 commit a3dc82d

File tree

4 files changed

+261
-69
lines changed

4 files changed

+261
-69
lines changed

.gitignore

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
.vscode
22
*.swp
3-
build-output
43
.ssh-remote
54
*~
6-
ocf-scheduler-cf-plugin
7-
builds
5+
/ocf-scheduler-cf-plugin
86
.DS_Store
7+
/releases/**

Makefile

Lines changed: 135 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,154 @@
1-
# This is how we want to name the binary output
2-
APP_NAME ?= ocf-scheduler-cf-plugin
3-
VERSION ?= `./scripts/genver`-dev
1+
PROJECT :=ocf-scheduler-cf-plugin
2+
SHELL :=/bin/bash
3+
GOOS :=$(shell go env GOOS)
4+
GOARCH :=$(shell go env GOARCH)
5+
GOMODULECMD :=main
6+
RELEASE_ROOT ?=releases
7+
DEV_TEST_BUILD =./$(PROJECT)
8+
TARGETS ?=linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64
9+
10+
define is_not_number
11+
$(shell echo ${1} | sed -e 's/[0123456789]//g')
12+
endef
13+
14+
ifneq ($(VERSION),)
15+
VERSION_SPLIT:=$(subst ., ,$(VERSION))
16+
ifneq ($(words $(VERSION_SPLIT)),3)
17+
$(error VERSION does not have 3 parts |$(words $(VERSION_SPLIT))|$(VERSION)|$(VERSION_SPLIT)|)
18+
endif
19+
else
20+
VERSION_TAG:=$(shell (git describe --tags --abbrev=0 2>/dev/null || echo 0.0.0) | sed -e "s/^v//")
21+
VERSION_SPLIT:=$(subst ., ,$(VERSION_TAG))
22+
ifneq ($(words $(VERSION_SPLIT)),3)
23+
$(error VERSION_TAG does not have 3 parts |$(words $(VERSION_SPLIT))|$(VERSION_TAG)|$(VERSION_SPLIT)|)
24+
endif
25+
26+
ifneq ($(words $(call is_not_number,$(word 3,$(VERSION_SPLIT)))), 0)
27+
$(error The VERSION_TAG patch version string contain non-numeric characters)
28+
endif
29+
30+
VERSION_SPLIT:=$(wordlist 1, 2, $(VERSION_SPLIT)) $(shell echo $$(($(word 3,$(VERSION_SPLIT))+1)))
31+
endif
32+
33+
ifneq ($(words $(call is_not_number,$(VERSION_SPLIT))), 0)
34+
$(error The version string contain non-numeric characters)
35+
endif
36+
37+
SEMVER_MAJOR ?=$(word 1,$(VERSION_SPLIT))
38+
SEMVER_MINOR ?=$(word 2,$(VERSION_SPLIT))
39+
SEMVER_PATCH ?=$(word 3,$(VERSION_SPLIT))
40+
SEMVER_PRERELEASE ?=
41+
SEMVER_BUILDMETA ?=
42+
BUILD_DATE :=$(shell date -u -Iseconds)
43+
BUILD_VCS_URL :=$(shell git config --get remote.origin.url)
44+
BUILD_VCS_ID :=$(shell git log -n 1 --date=iso-strict-local --format="%h")
45+
BUILD_VCS_ID_DATE :=$(shell TZ=UTC0 git log -n 1 --date=iso-strict-local --format='%ad')
46+
47+
build: SEMVER_PRERELEASE := dev
48+
49+
GO_LDFLAGS = -X '$(GOMODULECMD).SemVerMajor=$(SEMVER_MAJOR)' \
50+
-X '$(GOMODULECMD).SemVerMinor=$(SEMVER_MINOR)' \
51+
-X '$(GOMODULECMD).SemVerPatch=$(SEMVER_PATCH)' \
52+
-X '$(GOMODULECMD).SemVerPrerelease=$(SEMVER_PRERELEASE)' \
53+
-X '$(GOMODULECMD).SemVerBuild=$(SEMVER_BUILDMETA)' \
54+
-X '$(GOMODULECMD).BuildDate=$(BUILD_DATE)' \
55+
-X '$(GOMODULECMD).BuildVcsUrl=$(BUILD_VCS_URL)' \
56+
-X '$(GOMODULECMD).BuildVcsId=$(BUILD_VCS_ID)' \
57+
-X '$(GOMODULECMD).BuildVcsIdDate=$(BUILD_VCS_ID_DATE)'
58+
59+
# The build meta data is added when the build is done
60+
#
61+
SEMVER_VERSION := $(if $(SEMVER_MAJOR),$(SEMVER_MAJOR),$(error Missing SEMVER_MAJOR))
62+
SEMVER_VERSION := $(SEMVER_VERSION)$(if $(SEMVER_MINOR),.$(SEMVER_MINOR),$(error Missing SEMVER_MINOR))
63+
SEMVER_VERSION := $(SEMVER_VERSION)$(if $(SEMVER_PATCH),.$(SEMVER_PATCH),$(error Missing SEMVER_PATCH))
64+
SEMVER_VERSION := $(SEMVER_VERSION)$(if $(SEMVER_PRERELEASE),-$(SEMVER_PRERELEASE))
65+
66+
# GMake rules generally used for local development
67+
68+
.PHONY: build clean install acceptance-tests
69+
70+
build: BUILD_GO_LDFLAGS:=-ldflags="$(GO_LDFLAGS) -X '$(GOMODULECMD).GoOs=$(GOOS)' -X '$(GOMODULECMD).GoArch=$(GOARCH)'"
71+
72+
build: BUILD_RULE_CMD := CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) \
73+
go build $(BUILD_GO_LDFLAGS) -o $(DEV_TEST_BUILD)
474

5-
MODULE ?= github.com/cloudfoundry-community/ocf-scheduler-cf-plugin
6-
CMD_PATH ?= .
7-
CGO_ENABLED ?= 0
8-
BUILD_PATH=builds
9-
BUILD=${APP_NAME}-${VERSION}
10-
PACKAGE=${MODULE}/${CMD_PATH}
75+
build: clean
76+
@echo "Building $(DEV_TEST_BUILD)"
77+
$(BUILD_RULE_CMD)
1178

12-
SHELL:=/bin/bash
13-
GO_LDFLAGS := $(shell echo "-ldflags='-X main.Version=$(VERSION)'" | sed -e 's/-rc./-rc/') #plugins can't have periods after rc in version
79+
clean:
80+
@rm -f $(DEV_TEST_BUILD) || true
1481

15-
REMOTE_HOST := $(shell [ -f .ssh-remote ] && cat .ssh-remote || echo '')
16-
REMOTE_FOLDER := ~/programs/ocf-scheduler-cf-plugin/ocf-scheduler-cf-plugin
82+
install: build
83+
cf install-plugin $(DEV_TEST_BUILD) -f || true
1784

18-
build: clean
19-
go build $(GO_LDFLAGS) .
85+
acceptance-tests:
86+
go test -timeout 600s ./...
2087

21-
# Cleans our project: deletes binaries
22-
clean:
23-
rm -rf ${APP_NAME}
88+
# GMake rules for release building are below
89+
90+
.PHONY: distbuild require-% release-% ci-release clean distclean show-releases
91+
92+
require-%:
93+
@ if [ "${${*}}" = "" ]; then \
94+
echo "Environment variable $* not set"; \
95+
exit 1; \
96+
fi
2497

25-
# Releases
26-
release: distclean distbuild linux darwin windows
98+
RELEASES := $(foreach target,$(TARGETS),release-$(target)-$(PROJECT))
99+
100+
show-releases:
101+
@ls -lA $(RELEASE_ROOT)
102+
@echo ""
103+
104+
ci-release: require-VERSION release-all
105+
106+
release-all: release-clean distbuild $(RELEASES) show-releases
27107

28108
distbuild:
29-
mkdir -p ${BUILD_PATH}
109+
@mkdir -p $(RELEASE_ROOT)
30110

31-
distclean:
32-
rm -rf ${BUILD_PATH}
111+
# Arguments os,arch,build
112+
define build-target
113+
release-$(1)/$(2)-$(PROJECT): RELEASE_GO_LDFLAGS:=-ldflags="$(GO_LDFLAGS) -X '$(GOMODULECMD).GoOs=$(1)' -X '$(GOMODULECMD).GoArch=$(2)'"
33114

34-
linux:
35-
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ${GO_LDFLAGS} -o ${BUILD_PATH}/${BUILD}-linux-amd64 ${PACKAGE}
36-
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build ${GO_LDFLAGS} -o ${BUILD_PATH}/${BUILD}-linux-arm64 ${PACKAGE}
115+
release-$(1)/$(2)-$(PROJECT): RELEASE_EXECUTABLE_BASE:=$(RELEASE_ROOT)/$(PROJECT)-$(SEMVER_VERSION)+$(1).$(2)$(if $(3),.$(3))
37116

38-
darwin:
39-
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build ${GO_LDFLAGS} -o ${BUILD_PATH}/${BUILD}-darwin-amd64 ${PACKAGE}
40-
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build ${GO_LDFLAGS} -o ${BUILD_PATH}/${BUILD}-darwin-arm64 ${PACKAGE}
41-
42-
windows:
43-
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build ${GO_LDFLAGS} -o ${BUILD_PATH}/${BUILD}-windows-amd64.exe ${PACKAGE}
117+
release-$(1)/$(2)-$(PROJECT): RELEASE_EXECUTABLE:=$$(RELEASE_EXECUTABLE_BASE)$(if $(patsubst windows,,$(1)),,.exe)
44118

45-
docker-build:
46-
docker build -t ocf-scheduler-cf-plugin .
119+
release-$(1)/$(2)-$(PROJECT): RELEASE_EXECUTABLE_SHA1:=$$(RELEASE_EXECUTABLE_BASE).sha1
47120

48-
mkdir -p build-output
121+
release-$(1)/$(2)-$(PROJECT):
122+
@echo "Building $$(PROJECT) version $$(SEMVER_VERSION) for $(1) $(2) ..."
123+
@CGO_ENABLED=0 GOOS=$(1) GOARCH=$(2) go build -o $$(RELEASE_EXECUTABLE) $$(RELEASE_GO_LDFLAGS)
124+
@openssl sha1 -r $$(RELEASE_EXECUTABLE) > $$(RELEASE_EXECUTABLE_SHA1)
125+
endef
49126

50-
docker container create --name build ocf-scheduler-cf-plugin
51-
docker container cp build:/bin/ocf-scheduler-cf-plugin ./build-output
52-
docker container rm build
127+
$(foreach target,$(TARGETS), $(eval $(call build-target,$(word 1, $(subst /, ,$(target))),$(word 2, $(subst /, ,$(target))),$(SEMVER_BUILDMETA))))
53128

54-
install-remote:
55-
scp build-output/ocf-scheduler-cf-plugin $(REMOTE_HOST):$(REMOTE_FOLDER)/ocf-scheduler-cf-plugin
56-
ssh $(REMOTE_HOST) "cd $(REMOTE_FOLDER); cf uninstall-plugin OCFScheduler || true; yes | cf install-plugin ocf-scheduler-cf-plugin"
129+
release-clean:
130+
@rm -f $(RELEASE_ROOT)/$(PROJECT)-* || true
131+
@[[ ! -d $(RELEASE_ROOT) ]] || rmdir -p $(RELEASE_ROOT)
57132

58-
install:
59-
cf uninstall-plugin OCFScheduler || true
60-
yes | cf install-plugin ocf-scheduler-cf-plugin
133+
distclean: clean release-clean
61134

62-
acceptance-tests:
63-
go test -timeout 600s ./...
135+
# REMOTE_HOST := $(shell [ -f .ssh-remote ] && cat .ssh-remote || echo '')
136+
# REMOTE_FOLDER := ~/programs/ocf-scheduler-cf-plugin/ocf-scheduler-cf-plugin
137+
138+
# docker-build:
139+
# docker build -t ocf-scheduler-cf-plugin .
140+
#
141+
# mkdir -p build-output
142+
#
143+
# docker container create --name build ocf-scheduler-cf-plugin
144+
# docker container cp build:/bin/ocf-scheduler-cf-plugin ./build-output
145+
# docker container rm build
146+
147+
# install-remote:
148+
# scp build-output/ocf-scheduler-cf-plugin $(REMOTE_HOST):$(REMOTE_FOLDER)/ocf-scheduler-cf-plugin
149+
# ssh $(REMOTE_HOST) "cd $(REMOTE_FOLDER); cf uninstall-plugin OCFScheduler || true; yes | cf install-plugin ocf-scheduler-cf-plugin"
64150

65-
all: build install
151+
# run-remote: docker-build install-remote
152+
#
66153

67-
run-remote: docker-build install-remote
154+
.DEFAULT_GOAL := ci-release

README.md

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,65 @@ Clone the repo, build the binary, and install the plugin:
1010
```
1111
git clone https://github.com/cloudfoundry-community/ocf-scheduler-cf-plugin
1212
cd ocf-sceduler-cf-plugin
13-
make
1413
make install
1514
```
1615

16+
## Extended Build Metadata
17+
18+
The extended build metadata is available by executing the plugin itself.
19+
20+
```
21+
./ocf-scheduler-cf-plugin
22+
```
23+
24+
## Release Engineering Information
25+
26+
### GMake targets for pipelining
27+
28+
Generate release artifacts in the ***releases*** directory. Sha256 checksum files are
29+
created for each artifact as well.
30+
```
31+
gmake ci-release VERSION=<major.minor,patch> [SEMVER_PRERELEASE=<prerelease-metadata>] [SEMVER_BUILDMETA=<buid-metadata>]
32+
```
33+
34+
Cleans up after the artifacts are copied
35+
```
36+
gmake release-clean
37+
38+
```
39+
### GMake targets for manual release engineering
40+
41+
You can use the pipelining targets, but for manual release engineering testing the following
42+
additional targets can be used for release build testing.
43+
44+
Same as ci-release but the version information is picked up from the latest tag. The patch
45+
version is incremented to avoid version confusion for actual releases and the prerelease is set to dev.
46+
The same GMake variables used on ci-release can be used on release-all
47+
```
48+
gmake release-all
49+
```
50+
51+
## GMake targets for development engineering
52+
53+
In addtion to the release engineering targets, the following target will build the artifact for your local
54+
environment. The built artifact is located in the repo top directory. The install target will build and install
55+
the plugin into your local cf command. The same GMake variables for release engineering are available for development
56+
engineering.
57+
```
58+
gmake build
59+
./ocf-scheduler-cf-plugin
60+
```
61+
or
62+
```
63+
gmake install
64+
./ocf-scheduler-cf-plugin
65+
```
66+
67+
Clean up the build or install target generated artifacts
68+
```
69+
gmake clean
70+
```
71+
1772
## References
1873

1974
[CF Plugin API](https://github.com/cloudfoundry/cli/blob/master/plugin/plugin_examples/DOC.md) documentation

main.go

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ import (
2121

2222
var Version string = "v0.0.0"
2323

24+
var SemVerMajor string
25+
var SemVerMinor string
26+
var SemVerPatch string
27+
var SemVerPrerelease string
28+
var SemVerBuild string
29+
var BuildDate string
30+
var BuildVcsUrl string
31+
var BuildVcsId string
32+
var BuildVcsIdDate string
33+
var GoArch string
34+
var GoOs string
35+
2436
type OCFScheduler struct{}
2537

2638
// Setup to use the cf cli ui prompts
@@ -35,7 +47,11 @@ var ui terminal.UI
3547
func (c *OCFScheduler) GetMetadata() plugin.PluginMetadata {
3648
return plugin.PluginMetadata{
3749
Name: "OCFScheduler",
38-
Version: normalizeVersion(Version),
50+
Version: plugin.VersionType{
51+
Major: getVersion("Major", SemVerMajor),
52+
Minor: getVersion("Minor", SemVerMinor),
53+
Build: getVersion("Patch",SemVerPatch),
54+
},
3955
Commands: []plugin.Command{
4056
{
4157
Name: "create-job",
@@ -251,26 +267,61 @@ func (c *OCFScheduler) Run(cliConnection plugin.CliConnection, args []string) {
251267
}
252268
}
253269

254-
func main() {
255-
plugin.Start(new(OCFScheduler))
270+
func createBuildMeta(buildOs, buildArch, build string) string {
271+
p1 := strings.TrimSpace(buildOs)
272+
p2 := strings.TrimSpace(buildArch)
273+
p3 := strings.TrimSpace(build)
274+
if p1 == "" || p2 == "" {
275+
panic(fmt.Sprintf("Go meta data is missing one of its parts: %s, %s ", p1, p2))
276+
}
277+
b := strings.Join([]string{p1, p2}, ".")
278+
if p3 != "" {
279+
b += "." + p3
280+
}
281+
return b
256282
}
257283

258-
func normalizeVersion(version string) plugin.VersionType {
259-
if strings.ToLower(version)[0] == []byte("v")[0] {
260-
version = version[1:]
284+
func createSemVer(major, minor, patch, prerelease, build string) string {
285+
p1 := strings.TrimSpace(major)
286+
p2 := strings.TrimSpace(minor)
287+
p3 := strings.TrimSpace(patch)
288+
p4 := strings.TrimSpace(prerelease)
289+
p5 := strings.TrimSpace(build)
290+
if p1 == "" || p2 == "" || p3 == "" {
291+
panic(fmt.Sprintf("Semanic version is missing one of its parts: %s.%s.%s", p1, p2, p3))
292+
}
293+
294+
sv := strings.Join([]string{p1, p2, p3}, ".")
295+
if p4 != "" {
296+
sv += "-" + p4
261297
}
298+
if p5 != "" {
299+
sv += "+" + p5
300+
}
301+
return sv
302+
}
262303

263-
mmb := strings.Split(version, ".")
264-
if len(mmb) != 3 {
265-
panic("invalid version: " + version)
304+
func getVersion(version, toInt string) int {
305+
theInt, err := strconv.Atoi(toInt)
306+
if err != nil {
307+
theInt = 0
308+
fmt.Printf("Warning: %v for %v version value. Defaulting to a zero value\n", err.Error(), version)
266309
}
267-
major, _ := strconv.Atoi(mmb[0])
268-
minor, _ := strconv.Atoi(mmb[1])
269-
build, _ := strconv.Atoi(mmb[2])
270-
271-
return plugin.VersionType{
272-
Major: major,
273-
Minor: minor,
274-
Build: build,
310+
return theInt
311+
}
312+
313+
func main() {
314+
args := os.Args[1:]
315+
if len(args) == 0 {
316+
bm := createBuildMeta(GoOs, GoArch, SemVerBuild)
317+
sv := createSemVer(SemVerMajor, SemVerMinor, SemVerPatch, SemVerPrerelease, bm)
318+
f := "%13v %v\n"
319+
fmt.Printf(f, "Version:", sv)
320+
fmt.Printf(f, "Build Date:", BuildDate)
321+
fmt.Printf(f, "VCS Url:", BuildVcsUrl)
322+
fmt.Printf(f, "VCS Id:", BuildVcsId)
323+
fmt.Printf(f, "VCS Id Date:", BuildVcsIdDate)
275324
}
325+
326+
plugin.Start(new(OCFScheduler))
276327
}

0 commit comments

Comments
 (0)