diff --git a/.github/workflows/devconfig-comment-handler.yml b/.github/workflows/devconfig-comment-handler.yml new file mode 100644 index 000000000000..c24470ae1089 --- /dev/null +++ b/.github/workflows/devconfig-comment-handler.yml @@ -0,0 +1,321 @@ +name: DevConfig Comment Handler + +on: + issue_comment: + types: [created] + +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + check-comment: + runs-on: ubuntu-latest + if: contains(github.event.comment.body, '/add-devconfig') || contains(github.event.comment.body, '/delete-devconfig') || contains(github.event.comment.body, '/amend-devconfig') + outputs: + should_process: ${{ steps.check.outputs.should_process }} + pr_number: ${{ github.event.issue.number }} + has_custom_json: ${{ steps.extract-json.outputs.has_custom_json }} + custom_json: ${{ steps.extract-json.outputs.custom_json }} + command: ${{ steps.determine-command.outputs.command }} + steps: + - name: Check if comment is on a PR + id: check + run: | + if [ "${{ github.event.issue.pull_request != '' }}" = "true" ]; then + echo "should_process=true" >> $GITHUB_OUTPUT + echo "Comment is on PR #${{ github.event.issue.number }}" + else + echo "should_process=false" >> $GITHUB_OUTPUT + echo "Comment is not on a PR" + fi + + - name: Determine command + id: determine-command + if: steps.check.outputs.should_process == 'true' + run: | + # Save the comment to a file to avoid shell interpretation issues + echo '${{ github.event.comment.body }}' > comment_raw.txt + + # Convert Windows line endings to Unix and extract first line + tr -d '\r' < comment_raw.txt | head -n 1 > first_line.txt + FIRST_LINE=$(cat first_line.txt) + + echo "First line of comment: $FIRST_LINE" + + if [[ "$FIRST_LINE" == "/add-devconfig"* ]]; then + echo "command=add" >> $GITHUB_OUTPUT + echo "Command: add-devconfig" + elif [[ "$FIRST_LINE" == "/delete-devconfig"* ]]; then + echo "command=delete" >> $GITHUB_OUTPUT + echo "Command: delete-devconfig" + elif [[ "$FIRST_LINE" == "/amend-devconfig"* ]]; then + echo "command=amend" >> $GITHUB_OUTPUT + echo "Command: amend-devconfig" + else + echo "No valid command found in first line" + exit 1 + fi + + - name: Extract custom JSON + id: extract-json + if: steps.check.outputs.should_process == 'true' && (steps.determine-command.outputs.command == 'add' || steps.determine-command.outputs.command == 'amend') + run: | + # Save the comment to a file to avoid shell interpretation issues + echo '${{ github.event.comment.body }}' > comment.txt + + # Convert Windows line endings to Unix + tr -d '\r' < comment.txt > comment_unix.txt + + # Check if the comment contains JSON + if grep -q '```json' comment_unix.txt; then + echo "Found JSON block in comment" + + # Extract everything between ```json and ``` markers + # Use sed to extract the content between markers + sed -n '/```json/,/```/p' comment_unix.txt | sed '1d;$d' > extracted_json.txt + + if [ -s extracted_json.txt ]; then + echo "has_custom_json=true" >> $GITHUB_OUTPUT + echo "custom_json<> $GITHUB_OUTPUT + cat extracted_json.txt >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "JSON content extracted successfully" + else + echo "has_custom_json=false" >> $GITHUB_OUTPUT + echo "No JSON content found between markers" + fi + else + echo "has_custom_json=false" >> $GITHUB_OUTPUT + echo "No JSON block found in comment" + fi + + - name: Add processing comment to PR + if: steps.check.outputs.should_process == 'true' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const command = '${{ steps.determine-command.outputs.command }}'; + let message = ''; + + if (command === 'add') { + message = '⏳ Processing `/add-devconfig` command... DevConfig file is being generated and will be added to this PR shortly.'; + } else if (command === 'delete') { + message = '⏳ Processing `/delete-devconfig` command... DevConfig file will be removed from this PR shortly.'; + } else if (command === 'amend') { + message = '⏳ Processing `/amend-devconfig` command... DevConfig file is being updated in this PR.'; + } + + await github.rest.issues.createComment({ + issue_number: ${{ github.event.issue.number }}, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); + + process-comment: + needs: check-comment + if: needs.check-comment.outputs.should_process == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Get PR details + id: pr-details + run: | + PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}" + echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT + + # Get PR head ref + PR_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER") + HEAD_REF=$(echo "$PR_DATA" | jq -r .head.ref) + echo "pr_head_ref=$HEAD_REF" >> $GITHUB_OUTPUT + + echo "PR Number: $PR_NUMBER" + echo "PR Head Ref: $HEAD_REF" + + - name: Checkout PR branch + run: | + git fetch origin + git checkout ${{ steps.pr-details.outputs.pr_head_ref }} + + - name: Add DevConfig file + id: add-devconfig + if: needs.check-comment.outputs.command == 'add' + run: | + # Create DevConfig directory + mkdir -p ./generator/.DevConfigs + + # Use PR number for the filename + PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}" + DEVCONFIG_FILE="./generator/.DevConfigs/pr-${PR_NUMBER}.json" + + # Check if custom content was provided + if [ "${{ needs.check-comment.outputs.has_custom_json }}" == "true" ]; then + # Use the provided content + echo '${{ needs.check-comment.outputs.custom_json }}' > $DEVCONFIG_FILE + echo "Using custom DevConfig content from comment" + else + # Generate content based on detected changes + echo "Generating DevConfig content based on detected changes" + + # Get PR title as the changelog message + PR_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER") + COMMIT_MSG=$(echo "$PR_DATA" | jq -r .title) + + # If PR title is empty, fall back to the latest commit message + if [ -z "$COMMIT_MSG" ]; then + COMMIT_MSG=$(git log -1 --pretty=%B) + fi + + # Start building the DevConfig JSON + echo "{" > $DEVCONFIG_FILE + + # Check for core changes + CORE_CHANGES=$(git diff --name-only origin/main... | grep -v "^sdk/src/Services/" | wc -l || echo 0) + if [ $CORE_CHANGES -gt 0 ]; then + echo ' "core": {' >> $DEVCONFIG_FILE + echo ' "changeLogMessages": [' >> $DEVCONFIG_FILE + echo " \"$COMMIT_MSG\"" >> $DEVCONFIG_FILE + echo ' ],' >> $DEVCONFIG_FILE + echo ' "type": "patch",' >> $DEVCONFIG_FILE + echo ' "updateMinimum": true' >> $DEVCONFIG_FILE + echo ' }' >> $DEVCONFIG_FILE + fi + + # Check for service changes + SERVICE_CHANGES=$(git diff --name-only origin/main... | grep "^sdk/src/Services/" | wc -l || echo 0) + if [ $SERVICE_CHANGES -gt 0 ]; then + # If we added a core section, we need a comma + if [ $CORE_CHANGES -gt 0 ]; then + echo ',' >> $DEVCONFIG_FILE + fi + + echo ' "services": [' >> $DEVCONFIG_FILE + + # Extract service names + SERVICES=$(git diff --name-only origin/main... | grep "^sdk/src/Services/" | cut -d'/' -f4 | sort | uniq | jq -R -s -c 'split("\n") | map(select(length > 0))') + SERVICES_ARRAY=$(echo $SERVICES | jq -c '.') + + FIRST=true + echo $SERVICES_ARRAY | jq -c '.[]' | while read -r SERVICE; do + # Remove quotes from service name + SERVICE=$(echo $SERVICE | tr -d '"') + + if [ "$FIRST" == "true" ]; then + FIRST=false + else + echo ',' >> $DEVCONFIG_FILE + fi + + echo ' {' >> $DEVCONFIG_FILE + echo " \"serviceName\": \"$SERVICE\"," >> $DEVCONFIG_FILE + echo ' "type": "patch",' >> $DEVCONFIG_FILE + echo ' "changeLogMessages": [' >> $DEVCONFIG_FILE + echo " \"$COMMIT_MSG\"" >> $DEVCONFIG_FILE + echo ' ]' >> $DEVCONFIG_FILE + echo ' }' >> $DEVCONFIG_FILE + done + + echo ' ]' >> $DEVCONFIG_FILE + fi + + echo "}" >> $DEVCONFIG_FILE + fi + + # Format the JSON for better readability + cat $DEVCONFIG_FILE | jq . > ${DEVCONFIG_FILE}.formatted || cp $DEVCONFIG_FILE ${DEVCONFIG_FILE}.formatted + mv ${DEVCONFIG_FILE}.formatted $DEVCONFIG_FILE + + echo "Applied DevConfig file:" + cat $DEVCONFIG_FILE + + - name: Amend DevConfig file + id: amend-devconfig + if: needs.check-comment.outputs.command == 'amend' && needs.check-comment.outputs.has_custom_json == 'true' + run: | + # Create DevConfig directory if it doesn't exist + mkdir -p ./generator/.DevConfigs + + # Use PR number for the filename + PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}" + DEVCONFIG_FILE="./generator/.DevConfigs/pr-${PR_NUMBER}.json" + + # Use the provided content + echo '${{ needs.check-comment.outputs.custom_json }}' > $DEVCONFIG_FILE + echo "Using custom DevConfig content from comment" + + # Format the JSON for better readability + cat $DEVCONFIG_FILE | jq . > ${DEVCONFIG_FILE}.formatted || cp $DEVCONFIG_FILE ${DEVCONFIG_FILE}.formatted + mv ${DEVCONFIG_FILE}.formatted $DEVCONFIG_FILE + + echo "Updated DevConfig file:" + cat $DEVCONFIG_FILE + + - name: Delete DevConfig file + id: delete-devconfig + if: needs.check-comment.outputs.command == 'delete' + run: | + # Use PR number for the filename + PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}" + DEVCONFIG_FILE="./generator/.DevConfigs/pr-${PR_NUMBER}.json" + + if [ -f "$DEVCONFIG_FILE" ]; then + rm "$DEVCONFIG_FILE" + echo "DevConfig file deleted: $DEVCONFIG_FILE" + else + echo "DevConfig file not found: $DEVCONFIG_FILE" + exit 1 + fi + + - name: Commit and push changes + run: | + git config --global user.name "GitHub Action" + git config --global user.email "action@github.com" + + COMMAND="${{ needs.check-comment.outputs.command }}" + PR_NUMBER="${{ needs.check-comment.outputs.pr_number }}" + + if [ "$COMMAND" == "add" ]; then + git add ./generator/.DevConfigs/pr-${PR_NUMBER}.json + git commit -m "Add DevConfig file for PR #${PR_NUMBER}" + elif [ "$COMMAND" == "amend" ]; then + git add ./generator/.DevConfigs/pr-${PR_NUMBER}.json + git commit -m "Update DevConfig file for PR #${PR_NUMBER}" + elif [ "$COMMAND" == "delete" ]; then + git add -A ./generator/.DevConfigs/ + git commit -m "Remove DevConfig file for PR #${PR_NUMBER}" + fi + + git push origin ${{ steps.pr-details.outputs.pr_head_ref }} + + - name: Add confirmation comment to PR + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const command = '${{ needs.check-comment.outputs.command }}'; + let message = ''; + + if (command === 'add') { + message = '✅ DevConfig file has been added to this PR.'; + } else if (command === 'delete') { + message = '✅ DevConfig file has been removed from this PR.'; + } else if (command === 'amend') { + message = '✅ DevConfig file has been updated in this PR.'; + } + + await github.rest.issues.createComment({ + issue_number: ${{ needs.check-comment.outputs.pr_number }}, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); \ No newline at end of file diff --git a/.github/workflows/devconfig-validator.yml b/.github/workflows/devconfig-validator.yml new file mode 100644 index 000000000000..be53870e0162 --- /dev/null +++ b/.github/workflows/devconfig-validator.yml @@ -0,0 +1,219 @@ +name: DevConfig Validator + +on: + pull_request: + types: [synchronize, opened, reopened, edited] + +permissions: + contents: read + pull-requests: write + issues: write + +jobs: + validate-devconfig: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + outputs: + needs_devconfig: ${{ steps.check-needs.outputs.needs_devconfig }} + has_devconfig: ${{ steps.check-files.outputs.has_devconfig }} + devconfig_content: ${{ steps.generate-preview.outputs.devconfig_content }} + pr_number: ${{ github.event.pull_request.number }} + pr_head_ref: ${{ github.event.pull_request.head.ref }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for existing DevConfig files + id: check-files + run: | + # Check if .DevConfigs directory exists and has files + if [ -d "./generator/.DevConfigs" ] && [ "$(ls -A ./generator/.DevConfigs 2>/dev/null)" ]; then + echo "has_devconfig=true" >> $GITHUB_OUTPUT + echo "DevConfig files already exist in this PR" + else + echo "has_devconfig=false" >> $GITHUB_OUTPUT + echo "No DevConfig files found in this PR" + fi + + - name: Check if DevConfig is needed + id: check-needs + run: | + # Create .DevConfigs directory if it doesn't exist + mkdir -p ./generator/.DevConfigs + + # Debug current branch + CURRENT_BRANCH="${{ github.head_ref || github.ref_name }}" + echo "Current branch: $CURRENT_BRANCH" + + # Skip validation for specific branches + if [[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "development" || "$CURRENT_BRANCH" == "aws-sdk-net-v3.7" || "$CURRENT_BRANCH" == "aws-sdk-net-v3.7-development" ]]; then + echo "Branch $CURRENT_BRANCH is excluded from DevConfig validation" + echo "needs_devconfig=false" >> $GITHUB_OUTPUT + exit 0 + fi + + # Check for changes + echo "Checking for changes..." + + # Check for core changes + CORE_CHANGES=$(git diff --name-only origin/main... | grep -v "^sdk/src/Services/" | wc -l || echo 0) + echo "Core changes: $CORE_CHANGES" + + # Check for service changes + SERVICE_CHANGES=$(git diff --name-only origin/main... | grep "^sdk/src/Services/" | wc -l || echo 0) + echo "Service changes: $SERVICE_CHANGES" + + # Determine if DevConfig is needed + if [ $CORE_CHANGES -gt 0 ] || [ $SERVICE_CHANGES -gt 0 ]; then + echo "needs_devconfig=true" >> $GITHUB_OUTPUT + echo "Changes detected, DevConfig is needed" + else + echo "needs_devconfig=false" >> $GITHUB_OUTPUT + echo "No changes detected, DevConfig is not needed" + fi + + - name: Generate DevConfig preview + id: generate-preview + if: steps.check-needs.outputs.needs_devconfig == 'true' && steps.check-files.outputs.has_devconfig == 'false' + run: | + # Get PR title as the changelog message instead of merge commit message + COMMIT_MSG="${{ github.event.pull_request.title }}" + + # If PR title is empty, fall back to the latest commit message + if [ -z "$COMMIT_MSG" ]; then + COMMIT_MSG=$(git log -1 --pretty=%B) + fi + + # Start building the DevConfig JSON + echo "{" > devconfig-preview.json + + # Check for core changes + CORE_CHANGES=$(git diff --name-only origin/main... | grep -v "^sdk/src/Services/" | wc -l || echo 0) + if [ $CORE_CHANGES -gt 0 ]; then + echo ' "core": {' >> devconfig-preview.json + echo ' "changeLogMessages": [' >> devconfig-preview.json + echo " \"$COMMIT_MSG\"" >> devconfig-preview.json + echo ' ],' >> devconfig-preview.json + echo ' "type": "patch",' >> devconfig-preview.json + echo ' "updateMinimum": true' >> devconfig-preview.json + echo ' }' >> devconfig-preview.json + fi + + # Check for service changes + SERVICE_CHANGES=$(git diff --name-only origin/main... | grep "^sdk/src/Services/" | wc -l || echo 0) + if [ $SERVICE_CHANGES -gt 0 ]; then + # If we added a core section, we need a comma + if [ $CORE_CHANGES -gt 0 ]; then + echo ',' >> devconfig-preview.json + fi + + echo ' "services": [' >> devconfig-preview.json + + # Extract service names + SERVICES=$(git diff --name-only origin/main... | grep "^sdk/src/Services/" | cut -d'/' -f4 | sort | uniq | jq -R -s -c 'split("\n") | map(select(length > 0))') + SERVICES_ARRAY=$(echo $SERVICES | jq -c '.') + + FIRST=true + echo $SERVICES_ARRAY | jq -c '.[]' | while read -r SERVICE; do + # Remove quotes from service name + SERVICE=$(echo $SERVICE | tr -d '"') + + if [ "$FIRST" == "true" ]; then + FIRST=false + else + echo ',' >> devconfig-preview.json + fi + + echo ' {' >> devconfig-preview.json + echo " \"serviceName\": \"$SERVICE\"," >> devconfig-preview.json + echo ' "type": "patch",' >> devconfig-preview.json + echo ' "changeLogMessages": [' >> devconfig-preview.json + echo " \"$COMMIT_MSG\"" >> devconfig-preview.json + echo ' ]' >> devconfig-preview.json + echo ' }' >> devconfig-preview.json + done + + echo ' ]' >> devconfig-preview.json + fi + + echo "}" >> devconfig-preview.json + + # Format the JSON for better readability + jq . devconfig-preview.json > devconfig-formatted.json + mv devconfig-formatted.json devconfig-preview.json + + # Save the content to output + DEVCONFIG_CONTENT=$(cat devconfig-preview.json) + echo "devconfig_content<> $GITHUB_OUTPUT + echo "$DEVCONFIG_CONTENT" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + echo "DevConfig Preview:" + cat devconfig-preview.json + + - name: Post comment with DevConfig preview + if: steps.check-needs.outputs.needs_devconfig == 'true' && steps.check-files.outputs.has_devconfig == 'false' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const devConfigContent = `${{ steps.generate-preview.outputs.devconfig_content }}`; + + const commentBody = `## DevConfig File Needed + + This PR requires a DevConfig file. Here's a preview of the suggested DevConfig: + + \`\`\`json + ${devConfigContent} + \`\`\` + + For more information about DevConfig files, see the [DevConfig Files](https://github.com/aws/aws-sdk-net/blob/main/README.md#devconfig-files) section in the README.md. + + ### Options: + + 1. **Generate devconfig manually:** Use \`./buildtools/add-devconfig.bat\` to generate a devconfig file and commit it to your PR. + 2. **Accept as is**: Comment with \`/add-devconfig\` to add this preview DevConfig file to your PR. + 3. **Edit and accept**: Edit the JSON above, then comment with \`/add-devconfig\` followed by your edited JSON in a code block: + + \`\`\`\` + /add-devconfig + + \`\`\`json + { + "your": "edited JSON here. Use the preview for reference." + } + \`\`\` + \`\`\`\` + + ### Additional Commands: + + - **Delete DevConfig**: Comment with \`/delete-devconfig\` to remove the DevConfig file from your PR + - **Amend DevConfig**: Comment with \`/amend-devconfig\` followed by your edited JSON to update the DevConfig file + + \`\`\`\` + /amend-devconfig + + \`\`\`json + { + "your": "updated JSON here. Use the preview for reference." + } + \`\`\` + \`\`\`\` + `; + + github.rest.issues.createComment({ + issue_number: ${{ github.event.pull_request.number }}, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentBody + }); + + - name: Debug outputs + run: | + echo "PR Number: ${{ github.event.pull_request.number }}" + echo "PR Head Ref: ${{ github.event.pull_request.head.ref }}" + echo "Has DevConfig: ${{ steps.check-files.outputs.has_devconfig }}" + echo "Needs DevConfig: ${{ steps.check-needs.outputs.needs_devconfig }}" + echo "Current branch: ${{ github.head_ref || github.ref_name }}" \ No newline at end of file diff --git a/README.md b/README.md index d16883a287b1..1794467cdad8 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Please use these community resources for getting help. We use the [GitHub issues ### Opening Issues -If you encounter a bug with AWS SDK for .NET we would like to hear about it. Search the existing [issues](https://github.com/aws/aws-sdk-net/issues?q=is%3Aissue) and try to make sure your problem doesn’t already exist before opening a new issue. It’s helpful if you include the version of AWS SDK .NET and the OS you’re using. Please include a stack trace and reduced repro case when appropriate, too. +If you encounter a bug with AWS SDK for .NET we would like to hear about it. Search the existing [issues](https://github.com/aws/aws-sdk-net/issues?q=is%3Aissue) and try to make sure your problem doesn't already exist before opening a new issue. It's helpful if you include the version of AWS SDK .NET and the OS you're using. Please include a stack trace and reduced repro case when appropriate, too. The [GitHub issues][sdk-issues] are intended for bug reports and feature requests. For help and questions with using AWS SDK for .NET please make use of the resources listed in the Getting Help section. There are limited resources available for handling issues and by keeping the list of open issues clean we can respond in a timely manner. @@ -53,6 +53,125 @@ The SDK assemblies are strongly named which requires consumers of the SDK to rec Classes and interfaces with `Internal` in the namespace name are logically internal to the SDK but are often marked with a `public` access modifier, generally to allow the service-specific packages to use shared functionality in the Core package. Classes and interfaces in these namespaces are subject to modification or removal outside of versioning scheme described above. If you find yourself relying on `Internal` functionality directly, consider [opening a Feature Request](https://github.com/aws/aws-sdk-net/issues/new/choose) for your use case if one does not already exist. +## Making SDK Changes + +### DevConfig Files + +DevConfig files are required for all developer .NET SDK branches being merged into the system. These files control versioning for the change, changelog messages, which services are being updated, and other controls. The purpose of bringing developer configuration information into each developer's branch is so that any configuration and changelog messages the developer intends to release is reviewed by other developers reviewing their PR. + +DevConfig files are JSON files placed in the `./generator/.DevConfigs` folder. Each file must have a unique name to avoid merge conflicts. The file contains information about core and service changes, which helps the build system process and properly version bump the NuGet packages. + +#### DevConfig File Structure + +A DevConfig file can contain the following sections: + +**Core Section**: +Required for any change to the Core component of the SDK. + +```json +{ + "core": { + "changeLogMessages": [ + "Message 1", + "Message 2" + ], + "type": "patch", + "updateMinimum": true + } +} +``` + +- `changeLogMessages`: (Required) An array of messages to include in the changelog under the core section. +- `type`: (Required) The part of the version string to increment. Valid values are `minor` and `patch`. +- `updateMinimum`: (Required) Whether to update the minimum core version for all services. +- `backwardIncompatibilitiesToIgnore`: (Optional) An array of strings for the type of validation errors to ignore. + +**Service Section**: +Required for any change to a specific service. + +```json +{ + "services": [ + { + "serviceName": "S3Control", + "type": "patch", + "changeLogMessages": [ + "Fixed a bug causing a stack overflow when using the adaptive retry policy." + ] + }, + { + "serviceName": "S3", + "type": "patch", + "changeLogMessages": [ + "Fixed a bug where the bucketName was being marshalled incorrectly in operation xyz." + ] + } + ] +} +``` + +- `serviceName`: (Required) Name of the service without the "AWSSDK." prefix. +- `type`: (Required) The part of the version string to increment. Valid values are `minor` and `patch`. +- `changeLogMessages`: (Required) An array of messages to include in the changelog. + +**Other Special Sections**: + +- `overrideVersion`: Allows specifying a specific version to use for all services in the release. + +```json +{ + "services": [...], + "core": {...}, + "overrideVersion": "3.7.300.0" +} +``` + +#### Creating a DevConfig File + +You can use the provided script to generate a DevConfig file: + +``` +./buildtools/add-devconfig.bat +``` + +This will create a DevConfig file with a unique name in the correct location and populate it based on your changes. + +### DevConfig Validator + +The DevConfig Validator is a GitHub workflow that automatically checks if a DevConfig file is needed for your PR and helps you create one if necessary. The workflow detects changes to core and service files and determines if a DevConfig file is required. + +#### Workflow + +1. When you create or update a PR, the validator checks if a DevConfig file exists. +2. If no DevConfig file is found but changes require one, the validator adds a comment to your PR with a preview of the suggested DevConfig. +3. You can then add the DevConfig file using one of the provided commands. + +#### Commands + +The DevConfig Validator supports the following commands that you can use in PR comments: + +- `/add-devconfig`: Adds the preview DevConfig file to your PR. You can also provide your own JSON to customize the DevConfig. +- `/delete-devconfig`: Removes the DevConfig file from your PR. +- `/amend-devconfig`: Updates the existing DevConfig file with new JSON content. + +Example usage: + +```` +/add-devconfig + +```json +{ + "core": { + "changeLogMessages": [ + "Your custom changelog message" + ], + "type": "patch", + "updateMinimum": true + } +} +``` +```` + ## Code Analyzers Each service package includes a code analyzer that's automatically included when installing from NuGet. These analyzers are created based on the rules from the service model, and will generate a warning if you use a property value that's not valid (for example, shorter than the minimum length expected by the service). @@ -98,7 +217,7 @@ Unit tests can be found in the **AWSSDK.UnitTests** project. Protocol tests can be found in the `sdk/test/ProtocolTests` directory. Protocol tests ensure that each AWS protocol is working as expected. Each supported protocol is [listed here](https://smithy.io/2.0/aws/protocols/index.html). These tests are safe to run as they do not call real AWS services. You can run these tests by either opening the solution file and running the tests or via the `dotnet` cli by invoking `dotnet test AWSSDK.ProtocolTests.NetStandard.csproj`. The structure for the protocol test cases can be found [here in the smithy docs](https://smithy.io/2.0/additional-specs/http-protocol-compliance-tests.html). -### NuGet Packages +## NuGet Packages * [AWSSDK.AccessAnalyzer](https://www.nuget.org/packages/AWSSDK.AccessAnalyzer/) * Introducing AWS IAM Access Analyzer, an IAM feature that makes it easy for AWS customers to ensure that their resource-based policies provide only the intended access to resources outside their AWS accounts.