Skip to content

Commit

Permalink
Release Automation Tooling (#1226)
Browse files Browse the repository at this point in the history
* Go Module Generation for Smithy Artifacts
* Tooling for updating module dependency requirements
* Tooling for calculating releases
* Changelog tool for annotating module changes
  • Loading branch information
skmcgrail authored May 12, 2021
1 parent ea88d01 commit e1633ef
Show file tree
Hide file tree
Showing 56 changed files with 6,099 additions and 153 deletions.
77 changes: 76 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,24 @@ ENDPOINT_PREFIX_JSON=${CODEGEN_RESOURCES_PATH}/endpoint-prefix.json

LICENSE_FILE=$(shell pwd)/LICENSE.txt

RELEASE_MANIFEST_FILE ?=
RELEASE_CHGLOG_DESC_FILE ?=

.PHONY: all
all: generate unit

###################
# Code Generation #
###################
generate: smithy-generate gen-config-asserts copy-attributevalue-feature gen-repo-mod-replace gen-mod-dropreplace-smithy min-go-version-. tidy-modules-. add-module-license-files gen-aws-ptrs
.PHONY: generate smithy-generate smithy-build smithy-build-% smithy-clean smithy-go-publish-local format \
gen-config-asserts gen-repo-mod-replace gen-mod-replace-smithy gen-mod-dropreplace-smithy gen-aws-ptrs tidy-modules-% \
add-module-license-files sync-models sync-endpoints-model sync-endpoints.json clone-v1-models gen-endpoint-prefix.json \
sync-api-models copy-attributevalue-feature min-go-version-% update-requires smithy-annotate-stable \
update-module-metadata

generate: smithy-generate update-requires update-module-metadata smithy-annotate-stable gen-config-asserts \
copy-attributevalue-feature gen-repo-mod-replace gen-mod-dropreplace-smithy min-go-version-. tidy-modules-. \
add-module-license-files gen-aws-ptrs format

smithy-generate:
cd codegen && ./gradlew clean build -Plog-tests && ./gradlew clean
Expand All @@ -61,6 +73,10 @@ smithy-build-%: gen-repo-mod-replace
cd codegen && \
SMITHY_GO_BUILD_API="$(subst smithy-build-,,$@)" ./gradlew clean build -Plog-tests

smithy-annotate-stable:
cd ./internal/repotools && \
go run ./cmd/annotatestablegen

smithy-clean:
cd codegen && ./gradlew clean

Expand All @@ -69,6 +85,9 @@ smithy-go-publish-local:
git clone https://github.com/aws/smithy-go /tmp/smithy-go-local
make -C /tmp/smithy-go-local smithy-clean smithy-publish-local

format:
gofmt -w -s .

gen-config-asserts:
@echo "Generating SDK config package implementor assertions"
cd config \
Expand Down Expand Up @@ -152,10 +171,19 @@ min-go-version-%:
&& go run . -p $(subst _,/,$(subst min-go-version-,,$@)) ${EACHMODULE_FLAGS} \
"go mod edit -go=${SDK_MIN_GO_VERSION}"

update-requires:
cd ./internal/repotools && \
go run ./cmd/updaterequires

update-module-metadata:
cd ./internal/repotools && \
go run ./cmd/updatemodulemeta

################
# Unit Testing #
################
.PHONY: unit unit-race unit-test unit-race-test unit-race-modules-% unit-modules-% build build-modules-% \
go-build-modules-% test test-race-modules-% test-modules-% cachedep cachedep-modules-% api-diff-modules-%

unit: lint unit-modules-.
unit-race: lint unit-race-modules-.
Expand Down Expand Up @@ -264,6 +292,8 @@ api-diff-modules-%:
##############
# CI Testing #
##############
.PHONY: ci-test ci-test-no-generate ci-test-generate-validate

ci-test: generate unit-race ci-test-generate-validate
ci-test-no-generate: unit-race

Expand All @@ -279,6 +309,8 @@ ci-test-generate-validate:
#######################
# Integration Testing #
#######################
.PHONY: integration integ-modules-% cleanup-integ-buckets

integration: integ-modules-service

integ-modules-%:
Expand All @@ -298,6 +330,8 @@ cleanup-integ-buckets:
##############
# Benchmarks #
##############
.PHONY: bench bench-modules-%

bench: bench-modules-.

bench-modules-%:
Expand All @@ -310,9 +344,47 @@ bench-modules-%:
&& go run . -p $(subst _,/,$(subst bench-modules-,,$@)) ${EACHMODULE_FLAGS} \
"go test -timeout=10m -bench . --benchmem ${BUILD_TAGS} ${RUN_NONE} ./..."


#####################
# Release Process #
#####################
.PHONY: preview-release pre-release-validation release

preview-release:
@cd ./internal/repotools && \
go run ./cmd/calculaterelease

pre-release-validation:
@if [[ -z "${RELEASE_MANIFEST_FILE}" ]]; then \
echo "RELEASE_MANIFEST_FILE is required to specify the file to write the release manifest" && false; \
fi
@if [[ -z "${RELEASE_CHGLOG_DESC_FILE}" ]]; then \
echo "RELEASE_CHGLOG_DESC_FILE is required to specify the file to write the release notes" && false; \
fi

release: pre-release-validation
cd ./internal/repotools && \
go run ./cmd/calculaterelease -o ${RELEASE_MANIFEST_FILE} && \
go run ./cmd/updaterequires -release ${RELEASE_MANIFEST_FILE} && \
go run ./cmd/updatemodulemeta -release ${RELEASE_MANIFEST_FILE} && \
go run ./cmd/generatechangelog -release ${RELEASE_MANIFEST_FILE} -o ${RELEASE_CHGLOG_DESC_FILE} && \
go run ./cmd/changelog rm -all && \
go run ./cmd/tagrelease -release ${RELEASE_MANIFEST_FILE}

##############
# Repo Tools #
##############
.PHONY: install-repotools

install-repotools:
cd ./internal/repotools && \
go install ./cmd/changelog

##################
# Linting/Verify #
##################
.PHONY: verify lint vet vet-modules-% sdkv1check

verify: lint vet sdkv1check

lint:
Expand All @@ -339,6 +411,9 @@ sdkv1check:
###################
# Sandbox Testing #
###################
.PHONY: sandbox-tests sandbox-build-go1.15 sandbox-go1.15 sandbox-test-go1.15 sandbox-build-go1.16 \
sandbox-go1.16 sandbox-test-go1.16 sandbox-build-gotip sandbox-gotip sandbox-test-gotip update-aws-golang-tip

sandbox-tests: sandbox-test-go1.15 sandbox-test-go1.16 sandbox-test-gotip

sandbox-build-go1.15:
Expand Down
22 changes: 5 additions & 17 deletions codegen/copy_go_codegen.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
#!/bin/sh
#!/usr/bin/env bash

set -xe

SDK_ROOT=$1
CODGEN_ROOT=$2
SDK_PREFIX=$3

for MOD_PATH in $(find ${CODGEN_ROOT} -type f -name "go.mod" | xargs -I {} dirname {})
do
cd ${MOD_PATH}
MOD=$(grep -e "^module" go.mod | sed -e 's/^module *//')

DST=${SDK_ROOT}/${MOD#"$SDK_PREFIX"}

echo "Copying ${MOD} to ${DST}"

rm ${DST}/*.go
rm -rf ${DST}/types
rm -rf ${DST}/internal/endpoints
mkdir -p ${DST} 2>/dev/null
cp -r . ${DST}
done
cd "$1"/internal/repotools
go run ./cmd/gomodgen -build "$CODGEN_ROOT"
4 changes: 2 additions & 2 deletions codegen/protocol-test-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ tasks["build"].finalizedBy(tasks["buildSdk"])

// ensure built artifacts are put into the SDK's folders
tasks.create<Exec>("copyGoCodegen") {
dependsOn ("buildSdk")
commandLine ("$rootDir/copy_go_codegen.sh", "$rootDir/../", "$buildDir", "github.com/aws/aws-sdk-go-v2/")
dependsOn("buildSdk")
commandLine("$rootDir/copy_go_codegen.sh", "$rootDir/..", (tasks["buildSdk"] as SmithyBuild).outputDirectory.absolutePath)
}
tasks["buildSdk"].finalizedBy(tasks["copyGoCodegen"])
24 changes: 17 additions & 7 deletions codegen/sdk-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ import software.amazon.smithy.model.Model
import software.amazon.smithy.model.node.Node
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.gradle.tasks.SmithyBuild
import software.amazon.smithy.aws.traits.ServiceTrait
import kotlin.streams.toList

buildscript {
dependencies {
"classpath"("software.amazon.smithy:smithy-aws-traits:[1.5.1,2.0.0[")
}
}

plugins {
id("software.amazon.smithy") version "0.5.3"
}
Expand Down Expand Up @@ -70,18 +77,21 @@ tasks.register("generate-smithy-build") {
}
}

var (sdkId, version, remaining) = file.name.split(".")
sdkId = sdkId.replace("-", "").toLowerCase();
val serviceTrait = service.getTrait(ServiceTrait::class.javaObjectType).get();

val sdkId = serviceTrait.sdkId
.replace("-", "")
.replace(" ", "")
.toLowerCase();
val projectionContents = Node.objectNodeBuilder()
.withMember("imports", Node.fromStrings("${models.getAbsolutePath()}${File.separator}${file.name}"))
.withMember("imports", Node.fromStrings("${models.absolutePath}${File.separator}${file.name}"))
.withMember("plugins", Node.objectNode()
.withMember("go-codegen", Node.objectNodeBuilder()
.withMember("service", service.id.toString())
.withMember("module", "github.com/aws/aws-sdk-go-v2/service/" + sdkId.toLowerCase())
.withMember("moduleVersion", "1.0")
.withMember("module", "github.com/aws/aws-sdk-go-v2/service/$sdkId")
.build()))
.build()
projectionsBuilder.withMember(sdkId + "." + version.toLowerCase(), projectionContents)
projectionsBuilder.withMember(sdkId + "." + service.version.toLowerCase(), projectionContents)
}

file("smithy-build.json").writeText(Node.prettyPrintJson(Node.objectNodeBuilder()
Expand All @@ -99,6 +109,6 @@ tasks["build"]
// ensure built artifacts are put into the SDK's folders
tasks.create<Exec>("copyGoCodegen") {
dependsOn ("buildSdk")
commandLine ("$rootDir/copy_go_codegen.sh", "$rootDir/../", "$buildDir", "github.com/aws/aws-sdk-go-v2/")
commandLine ("$rootDir/copy_go_codegen.sh", "$rootDir/..", (tasks["buildSdk"] as SmithyBuild).outputDirectory.absolutePath)
}
tasks["buildSdk"].finalizedBy(tasks["copyGoCodegen"])
73 changes: 73 additions & 0 deletions internal/repotools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Repository Management Tools

This Go module is a collection of tools that have been written for managing the AWS SDK for Go V2 source repository.
At the time these were written, the Go ecosystem lacked tooling for managing repositories containing multiple Go modules
with at the size and scale of the AWS SDK. With over 274 Go modules in the repository the tooling found here has been
made to manage the lifecycle of managing dependencies (iter-repository and external), managing the releases of new
changes, tag management following Go semver requirements, and production of changelogs.

## Utilities
The following is a breakdown of some the key utilities found in this module that are used to manage the SDK and handle
the complex release process.

Commands | Description | README
--- | --- | ---
`changelog` | Create and manage changelog annotations. Annotations are used to document module changes and refining of the next semver version. | [Link][changelog]
`updaterequires` | Manages `go.mod` require entries, allows for easily updating inter-repository module dependencies to their latest tag, and the ability to quickly manage external dependency requirements. | N/A
`updatemodulemeta` | Generates a `go_module_metadata.go` file in each module containing useful runtime metadata like the modules tagged version. | N/A
`generatechangelog` | Uses a release description and associated changelog annotations to produce `CHANGELOG.md` entries for the release in each repository module. In addition, a summarized release statement will be created at the root of the repository. | N/A
`gomodgen` | Copies [smithy-go] codegen build artifacts into the SDK repository and generates a `go.mod` file using the build artifacts `generated.json` description. | N/A
`annotatestablegen` | Generates a release changelog annotation type for **new** [smithy-go] generated modules that are not marked as unstable. | N/A
`calculaterelease` | Detects new and changed Go modules in the repository, associates changelog annotations, and computes the next semver version tag for each module. Produces a release manifest that is used with other utilities to orchestrate a release. | [Link][calculaterelease]
`tagrelease` | Commits pending changes to the working directory, reads the release manifest, and creates the computed tags | N/A
`makerelative` | Used to generate `go.mod` `replace` statements for inter-repository module dependencies. This ensures that when developing on a given Go module it's iter-repository dependencies refer to the cloned repository. | N/A
`eachmodule` | Utility for quickly scripting execution of commands in each module of a repository. | N/A

# Configuration

A number of the repository tools, specifically those involved with the dependency management and release have specific
behavior that is driven by the `modman.toml` file found at the root of the git repository. This configuration file is
a [TOML] configuration file.

## Dependencies
The `dependencies` is a dictionary of key-value pairs that describe **external** dependencies that one or more modules
within the repository may depend on. (External dependencies is defined as the set of Go modules that are not found
within the project git repository.) This section is used to quickly set the version of a dependency modules in the
repository should use. The `updaterequires` tool can be used to update all Go modules require statements for each module
in the repository and update them to the indicated version if they depend on the given external module.

### Example
```toml
[dependencies]
"github.com/aws/smithy-go" = "v1.4.0"
```

This example indicates that repository modules that depend on `github.com/aws/smithy-go` should depend on `v1.4.0`
version of the library. After updating the value in the configuration file, `updaterequires` can be used to update
modules with this information.

## Modules

`modules` is a dictionary where the keys are module directories relative to the repository root. Each key maps to a
dictionary of key-value pairs that can configure several properties of a module that affect how or
if a module is handled when performing a release.

### Example
To configure the module `feature/service/shinything` to not be tagged by the release process:

```toml
[modules."feature/service/shinything"]
no_tag = true
```

For more information on how to configure how modules are released see the [calculaterelease README][calculaterelease].

#### Mark a module to be

**NOTE**: If you wish to create a configuration item for a module located at the root of the repository use
`.` as the key name.

[calculaterelease]: cmd/calculaterelease/README.md
[changelog]: cmd/changelog/README.md
[smithy-go]: https://github.com/aws/smithy-go
[TOML]: https://toml.io
Loading

0 comments on commit e1633ef

Please sign in to comment.