diff --git a/.github/workflows/sem_ver.yml b/.github/workflows/sem_ver.yml new file mode 100644 index 000000000..8f0142c54 --- /dev/null +++ b/.github/workflows/sem_ver.yml @@ -0,0 +1,53 @@ +# This workflow tests the installation of semantic release +name: Semantic Release Test Installation + +on: + pull_request: + +jobs: + semantic-release: + runs-on: macos-latest + permissions: + id-token: write + contents: read + steps: + - name: Support longpaths on Git checkout + run: | + git config --global core.longpaths true + - uses: actions/checkout@v4 + with: + submodules: recursive + + # We need access to the role that is able to get CI Bot Creds + - name: Configure AWS Credentials for Release + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::587316601012:role/GitHub-CI-CI-Bot-Credential-Access-Role-us-west-2 + role-session-name: CI_Bot_Release + + - name: Upgrade Node + uses: actions/setup-node@v4 + with: + node-version: 21 + + # Use AWS Secrets Manger GHA to retrieve CI Bot Creds + - name: Get CI Bot Creds Secret + uses: aws-actions/aws-secretsmanager-get-secrets@v2 + with: + secret-ids: Github/aws-crypto-tools-ci-bot + parse-json-secrets: true + + # Log in as the CI Bot + - name: Log in as CI Bot + run: | + echo ${{env.GITHUB_AWS_CRYPTO_TOOLS_CI_BOT_ESDK_RELEASE_TOKEN}} > token.txt + gh auth login --with-token < token.txt + rm token.txt + gh auth status + + # Test to see if we can setup semantic release + - name: Test Semantic Release Installation + uses: actions/checkout@v4 + - run: | + make setup_semantic_release diff --git a/.github/workflows/semantic_release.yml b/.github/workflows/semantic_release.yml new file mode 100644 index 000000000..5e9a9bcec --- /dev/null +++ b/.github/workflows/semantic_release.yml @@ -0,0 +1,77 @@ +# This workflow runs semantic release, bumps, generates changelog, and tags the project +name: Semantic Release + +on: + workflow_dispatch: + inputs: + dry-run: + description: "Is this a dry run to validate semantic-release behaves as expected? (y/n)" + required: true + type: string + +jobs: + semantic-release: + # there is no easy way in gha to check if the actor is part of the team, running semantic release is a more + # privileged operation, so we must make sure this list of users is a subset of the users labeled as maintainers of + # https://github.com/orgs/aws/teams/aws-crypto-tools + if: contains('["seebees","texastony","ShubhamChaturvedi7","lucasmcdonald3","josecorella","imabhichow","rishav-karanjit","antonf-amzn","justplaz","ajewellamz","RitvikKapila"]', github.actor) + runs-on: macos-latest + permissions: + id-token: write + contents: write + steps: + - name: Support longpaths on Git checkout + run: | + git config --global core.longpaths true + - uses: actions/checkout@v3 + # We only pull in the submodules we need to build the library + - run: git submodule update --init libraries + + # We need access to the role that is able to get CI Bot Creds + - name: Configure AWS Credentials for Release + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::587316601012:role/GitHub-CI-CI-Bot-Credential-Access-Role-us-west-2 + role-session-name: CI_Bot_Release + + - name: Upgrade Node + uses: actions/setup-node@v4 + with: + node-version: 21 + + # Use AWS Secrets Manger GHA to retrieve CI Bot Creds + - name: Get CI Bot Creds Secret + uses: aws-actions/aws-secretsmanager-get-secrets@v2 + with: + secret-ids: Github/aws-crypto-tools-ci-bot + parse-json-secrets: true + + # Log in as the CI Bot + - name: Log in as CI Bot + run: | + echo ${{env.GITHUB_AWS_CRYPTO_TOOLS_CI_BOT_ESDK_RELEASE_TOKEN}} > token.txt + gh auth login --with-token < token.txt + rm token.txt + gh auth status + + # Set up semantic release + - name: Setup Semantic Release + run: | + make setup_semantic_release + + # Run semantic release in dry run mode if input matches + - name: Run Semantic Release in dry run mode + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + if: ${{inputs.dry-run == 'y'}} + run: | + make dry_run_semantic_release + + # Run semantic release if input matches + - name: Run Semantic Release + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + if: ${{inputs.dry-run == 'n'}} + run: | + make run_semantic_release diff --git a/.releaserc.cjs b/.releaserc.cjs new file mode 100644 index 000000000..1c44fd796 --- /dev/null +++ b/.releaserc.cjs @@ -0,0 +1,160 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +/* + First run `make setup_semantic_release` to install the required dependencies. + + Using this config semantic-release will search for the latest tag + evaluate all commits after that tag + generate release notes and a version bump. + It will commit these changes, push these changes, and publish a new version tag. + + This file requires a `--branches` option to function. + This is to facilitate point releases if needed. + + `npx semantic-release --branches main` +*/ + +// This project has several runtimes +// each one has files that need to be updated. +// We model all the files and the runtimes here in this structure +const Runtimes = { + java: { + "project.properties": { + dependencies: [], + }, + }, + net: { + "DynamoDbEncryption/runtimes/net/DynamoDbEncryption.csproj": { + dependencies: [], + assemblyInfo: "DynamoDbEncryption/runtimes/net/AssemblyInfo.cs", + } + }, +}; + +/** + * @type {import('semantic-release').GlobalConfig} + */ +module.exports = { + branches: ["main"], + repositoryUrl: + "git@github.com:aws/aws-database-encryption-sdk-dynamodb.git", + plugins: [ + // Check the commits since the last release + ["@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "parserOpts": { + "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"] + }, + "presetConfig": { + "types": [ + {"type": "feat", "section": "Features"}, + {"type": "fix", "section": "Fixes"}, + {"type": "chore", "section": "Maintenance"}, + {"type": "docs", "section": "Maintenance"}, + {"type": "revert", "section": "Fixes"}, + {"type": "style", "hidden": true}, + {"type": "refactor", "hidden": true}, + {"type": "perf", "hidden": true}, + {"type": "test", "hidden": true} + ] + }, + "releaseRules": [ + {"type": "docs", "release": "patch"}, + {"type": "revert", "release": "patch"}, + {"type": "chore", "release": "patch"} + ] + }, + ], + // Based on the commits generate release notes + ["@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "parserOpts": { + "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"] + }, + "presetConfig": { + "types": [ + {"type": "feat", "section": "Features"}, + {"type": "fix", "section": "Fixes"}, + {"type": "chore", "section": "Maintenance"}, + {"type": "docs", "section": "Maintenance"}, + {"type": "revert", "section": "Fixes"}, + {"type": "style", "hidden": true}, + {"type": "refactor", "hidden": true}, + {"type": "perf", "hidden": true}, + {"type": "test", "hidden": true} + ] + } + } + ], + // Update the change log with the generated release notes + [ + "@semantic-release/changelog", + { + changelogFile: "CHANGELOG.md", + changelogTitle: "# Changelog", + }, + ], + + // Bump the various versions + [ + "semantic-release-replace-plugin", + { + replacements: [ + // Update the version for all Gradle Java projects + // Does not update the dependencies + { + files: Object.keys(Runtimes.java), + from: "projectJavaVersion=.*", + to: 'projectJavaVersion=${nextRelease.version}', + results: Object.keys(Runtimes.java).map(CheckResults), + countMatches: true, + }, + // Update the version for all DotNet projects + // Does not update the dependencies + { + files: Object.keys(Runtimes.net), + from: ".*", + to: "${nextRelease.version}", + results: Object.keys(Runtimes.net).map(CheckResults), + countMatches: true, + }, + // Update the AssmeblyInfo.cs file of the DotNet projects + ...Object.entries(Runtimes.net).flatMap( + ([file, { assemblyInfo }]) => ({ + files: assemblyInfo, + from: "assembly: AssemblyVersion(.*)", + to: 'assembly: AssemblyVersion("${nextRelease.version}")]', + results: [CheckResults(assemblyInfo)], + countMatches: true, + }), + ), + ], + }, + ], + // Commit and push changes the changelog and versions bumps + [ + "@semantic-release/git", + { + assets: [ + "CHANGELOG.md", + ...Object.values(Runtimes).flatMap((r) => Object.keys(r)), + ...Object.values(Runtimes.net).flatMap((r) => r.assemblyInfo), + ], + message: + "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}", + }, + ], + ], +}; + +function CheckResults(file) { + return { + file, + hasChanged: true, + numMatches: 1, + numReplacements: 1, + }; +} diff --git a/Makefile b/Makefile index 9b0efd9da..c95099be4 100644 --- a/Makefile +++ b/Makefile @@ -51,3 +51,12 @@ generate_properties_file: --namespace aws.polymorph \ --properties-file $(PROJECT_ROOT)/smithy-dafny-project.properties \ "; + +setup_semantic_release: + npm i --no-save semantic-release @semantic-release/changelog semantic-release-replace-plugin conventional-changelog-conventionalcommits @semantic-release/git + +run_semantic_release: + npx semantic-release --no-ci + +dry_run_semantic_release: + npx semantic-release --dry-run