diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..ac659ac848b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "swift" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 5c6479f9fb9..a9f839d2349 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -18,13 +18,19 @@ jobs: strategy: fail-fast: false matrix: - # This matrix runs tests on Mac, on oldest & newest supported Xcodes + # This matrix runs tests on iOS sim & Mac, on oldest & newest supported Xcodes runner: - macos-13-xlarge - macos-14-xlarge xcode: - Xcode_14.1 - Xcode_15.3 + destination: + - 'platform=iOS Simulator,OS=16.1,name=iPhone 14' + - 'platform=iOS Simulator,OS=17.4,name=iPhone 15' + - 'platform=tvOS Simulator,OS=16.1,name=Apple TV 4K (3rd generation) (at 1080p)' + - 'platform=tvOS Simulator,OS=17.4,name=Apple TV 4K (3rd generation) (at 1080p)' + - 'platform=OS X' exclude: # Don't run old macOS with new Xcode - runner: macos-13-xlarge @@ -32,6 +38,16 @@ jobs: # Don't run new macOS with old Xcode - runner: macos-14-xlarge xcode: Xcode_14.1 + # Don't run old simulators with new Xcode + - destination: 'platform=tvOS Simulator,OS=16.1,name=Apple TV 4K (3rd generation) (at 1080p)' + xcode: Xcode_15.3 + - destination: 'platform=iOS Simulator,OS=16.1,name=iPhone 14' + xcode: Xcode_15.3 + # Don't run new simulators with old Xcode + - destination: 'platform=tvOS Simulator,OS=17.4,name=Apple TV 4K (3rd generation) (at 1080p)' + xcode: Xcode_14.1 + - destination: 'platform=iOS Simulator,OS=17.4,name=iPhone 15' + xcode: Xcode_14.1 steps: - name: Configure AWS Credentials for Integration Tests uses: aws-actions/configure-aws-credentials@v4 @@ -80,12 +96,28 @@ jobs: java-version: 17 - name: Tools Versions run: ./scripts/ci_steps/log_tool_versions.sh + - name: Add Credentials to Test Plan + run: | + # JSON-escape the credentials. They are also surrounded with double quotes. + AKID_ESCAPED=`echo -n "$AWS_ACCESS_KEY_ID" | jq -Rsa .` + SECRET_ESCAPED=`echo -n "$AWS_SECRET_ACCESS_KEY" | jq -Rsa .` + REGION_ESCAPED=`echo -n "$AWS_DEFAULT_REGION" | jq -Rsa .` + TOKEN_ESCAPED=`echo -n "$AWS_SESSION_TOKEN" | jq -Rsa .` + # Insert the credentials into the .xctestplan file, write the modified JSON + # to a temp file, then move the temp over the original. + jq ".defaultOptions.environmentVariableEntries += [{\"key\": \"AWS_ACCESS_KEY_ID\", \"value\": $AKID_ESCAPED}, {\"key\": \"AWS_SECRET_ACCESS_KEY\", \"value\": $SECRET_ESCAPED}, {\"key\": \"AWS_DEFAULT_REGION\", \"value\": $REGION_ESCAPED}, {\"key\": \"AWS_SESSION_TOKEN\", \"value\": $TOKEN_ESCAPED}]" XCTestPlans/AWSIntegrationTestsOnCI.xctestplan > testplan.tmp + mv testplan.tmp XCTestPlans/AWSIntegrationTestsOnCI.xctestplan - name: Prepare Integration Tests run: ./scripts/ci_steps/prepare_integration_tests.sh - - name: Build Integration Tests - run: swift build --build-tests - name: Run Integration Tests - run: swift test + run: | + set -o pipefail && \ + NSUnbufferedIO=YES xcodebuild \ + -scheme AWSIntegrationTestsOnCI \ + -testPlan AWSIntegrationTestsOnCI \ + -destination '${{ matrix.destination }}' \ + test 2>&1 \ + | xcpretty linux: runs-on: ubuntu-latest diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/AWSIntegrationTestsOnCI.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/AWSIntegrationTestsOnCI.xcscheme new file mode 100644 index 00000000000..36aa0c50031 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/AWSIntegrationTestsOnCI.xcscheme @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Sources/Services/AWSS3/models/Models.swift b/Sources/Services/AWSS3/models/Models.swift index aaa9082698b..f8e729baf72 100644 --- a/Sources/Services/AWSS3/models/Models.swift +++ b/Sources/Services/AWSS3/models/Models.swift @@ -1911,7 +1911,7 @@ extension CopyObjectInput { items.add(Header(name: "x-amz-source-expected-bucket-owner", value: Swift.String(expectedSourceBucketOwner))) } if let expires = value.expires { - items.add(Header(name: "Expires", value: Swift.String(TimestampFormatter(format: .httpDate).string(from: expires)))) + items.add(Header(name: "Expires", value: Swift.String(expires))) } if let grantFullControl = value.grantFullControl { items.add(Header(name: "x-amz-grant-full-control", value: Swift.String(grantFullControl))) @@ -2076,7 +2076,7 @@ public struct CopyObjectInput { /// The account ID of the expected source bucket owner. If the account ID that you provide does not match the actual owner of the source bucket, the request fails with the HTTP status code 403 Forbidden (access denied). public var expectedSourceBucketOwner: Swift.String? /// The date and time at which the object is no longer cacheable. - public var expires: ClientRuntime.Date? + public var expires: Swift.String? /// Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object. /// /// * This functionality is not supported for directory buckets. @@ -2205,7 +2205,7 @@ public struct CopyObjectInput { copySourceSSECustomerKeyMD5: Swift.String? = nil, expectedBucketOwner: Swift.String? = nil, expectedSourceBucketOwner: Swift.String? = nil, - expires: ClientRuntime.Date? = nil, + expires: Swift.String? = nil, grantFullControl: Swift.String? = nil, grantRead: Swift.String? = nil, grantReadACP: Swift.String? = nil, @@ -2732,7 +2732,7 @@ extension CreateMultipartUploadInput { items.add(Header(name: "x-amz-expected-bucket-owner", value: Swift.String(expectedBucketOwner))) } if let expires = value.expires { - items.add(Header(name: "Expires", value: Swift.String(TimestampFormatter(format: .httpDate).string(from: expires)))) + items.add(Header(name: "Expires", value: Swift.String(expires))) } if let grantFullControl = value.grantFullControl { items.add(Header(name: "x-amz-grant-full-control", value: Swift.String(grantFullControl))) @@ -2841,7 +2841,7 @@ public struct CreateMultipartUploadInput { /// The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied). public var expectedBucketOwner: Swift.String? /// The date and time at which the object is no longer cacheable. - public var expires: ClientRuntime.Date? + public var expires: Swift.String? /// Specify access permissions explicitly to give the grantee READ, READ_ACP, and WRITE_ACP permissions on the object. By default, all objects are private. Only the owner has full access control. When uploading an object, you can use this header to explicitly grant access permissions to specific Amazon Web Services accounts or groups. This header maps to specific permissions that Amazon S3 supports in an ACL. For more information, see [Access Control List (ACL) Overview](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html) in the Amazon S3 User Guide. You specify each grantee as a type=value pair, where the type is one of the following: /// /// * id – if the value specified is the canonical user ID of an Amazon Web Services account @@ -3025,7 +3025,7 @@ public struct CreateMultipartUploadInput { contentLanguage: Swift.String? = nil, contentType: Swift.String? = nil, expectedBucketOwner: Swift.String? = nil, - expires: ClientRuntime.Date? = nil, + expires: Swift.String? = nil, grantFullControl: Swift.String? = nil, grantRead: Swift.String? = nil, grantReadACP: Swift.String? = nil, @@ -17961,7 +17961,7 @@ extension PutObjectInput { items.add(Header(name: "x-amz-expected-bucket-owner", value: Swift.String(expectedBucketOwner))) } if let expires = value.expires { - items.add(Header(name: "Expires", value: Swift.String(TimestampFormatter(format: .httpDate).string(from: expires)))) + items.add(Header(name: "Expires", value: Swift.String(expires))) } if let grantFullControl = value.grantFullControl { items.add(Header(name: "x-amz-grant-full-control", value: Swift.String(grantFullControl))) @@ -18218,7 +18218,7 @@ public struct PutObjectInput { /// The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied). public var expectedBucketOwner: Swift.String? /// The date and time at which the object is no longer cacheable. For more information, see [https://www.rfc-editor.org/rfc/rfc7234#section-5.3](https://www.rfc-editor.org/rfc/rfc7234#section-5.3). - public var expires: ClientRuntime.Date? + public var expires: Swift.String? /// Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object. /// /// * This functionality is not supported for directory buckets. @@ -18297,7 +18297,7 @@ public struct PutObjectInput { contentMD5: Swift.String? = nil, contentType: Swift.String? = nil, expectedBucketOwner: Swift.String? = nil, - expires: ClientRuntime.Date? = nil, + expires: Swift.String? = nil, grantFullControl: Swift.String? = nil, grantRead: Swift.String? = nil, grantReadACP: Swift.String? = nil, @@ -22559,7 +22559,7 @@ extension WriteGetObjectResponseInput { items.add(Header(name: "x-amz-fwd-header-x-amz-expiration", value: Swift.String(expiration))) } if let expires = value.expires { - items.add(Header(name: "x-amz-fwd-header-Expires", value: Swift.String(TimestampFormatter(format: .httpDate).string(from: expires)))) + items.add(Header(name: "x-amz-fwd-header-Expires", value: Swift.String(expires))) } if let lastModified = value.lastModified { items.add(Header(name: "x-amz-fwd-header-Last-Modified", value: Swift.String(TimestampFormatter(format: .httpDate).string(from: lastModified)))) @@ -22683,7 +22683,7 @@ public struct WriteGetObjectResponseInput { /// If the object expiration is configured (see PUT Bucket lifecycle), the response includes this header. It includes the expiry-date and rule-id key-value pairs that provide the object expiration information. The value of the rule-id is URL-encoded. public var expiration: Swift.String? /// The date and time at which the object is no longer cacheable. - public var expires: ClientRuntime.Date? + public var expires: Swift.String? /// The date and time that the object was last modified. public var lastModified: ClientRuntime.Date? /// A map of metadata to store with the object in S3. @@ -22775,7 +22775,7 @@ public struct WriteGetObjectResponseInput { errorCode: Swift.String? = nil, errorMessage: Swift.String? = nil, expiration: Swift.String? = nil, - expires: ClientRuntime.Date? = nil, + expires: Swift.String? = nil, lastModified: ClientRuntime.Date? = nil, metadata: [Swift.String:Swift.String]? = nil, missingMeta: Swift.Int? = nil, diff --git a/XCTestPlans/AWSIntegrationTestsOnCI.xctestplan b/XCTestPlans/AWSIntegrationTestsOnCI.xctestplan new file mode 100644 index 00000000000..5902e2b04fb --- /dev/null +++ b/XCTestPlans/AWSIntegrationTestsOnCI.xctestplan @@ -0,0 +1,95 @@ +{ + "configurations" : [ + { + "id" : "FF4C1A8F-5D70-4A2A-BFDE-77467500C547", + "name" : "Test Scheme Action", + "options" : { + } + } + ], + "defaultOptions" : { + "environmentVariableEntries" : [ + + ] + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSS3IntegrationTests", + "name" : "AWSS3IntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSCloudFrontKeyValueStoreIntegrationTests", + "name" : "AWSCloudFrontKeyValueStoreIntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSEC2IntegrationTests", + "name" : "AWSEC2IntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSECSIntegrationTests", + "name" : "AWSECSIntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSEventBridgeIntegrationTests", + "name" : "AWSEventBridgeIntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSKinesisIntegrationTests", + "name" : "AWSKinesisIntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSMediaConvertIntegrationTests", + "name" : "AWSMediaConvertIntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSRoute53IntegrationTests", + "name" : "AWSRoute53IntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSSQSIntegrationTests", + "name" : "AWSSQSIntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSSTSIntegrationTests", + "name" : "AWSSTSIntegrationTests" + } + }, + { + "target" : { + "containerPath" : "container:", + "identifier" : "AWSTranscribeStreamingIntegrationTests", + "name" : "AWSTranscribeStreamingIntegrationTests" + } + } + ], + "version" : 1 +} diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3Expires.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3Expires.kt index 58f00ebfbd0..3f2729eccc2 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3Expires.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3Expires.kt @@ -5,7 +5,6 @@ import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.transform.ModelTransformer import software.amazon.smithy.swift.codegen.SwiftSettings import software.amazon.smithy.swift.codegen.integration.SwiftIntegration -import software.amazon.smithy.swift.codegen.model.defaultName import software.amazon.smithy.swift.codegen.model.expectShape class S3Expires : SwiftIntegration { @@ -15,10 +14,9 @@ class S3Expires : SwiftIntegration { } override fun preprocessModel(model: Model, settings: SwiftSettings): Model { - // Find all the members named "Expires" in all of the output structures + // Find all the members named "Expires" in all of the structures // and change their shape from `Timestamp` to `String` val updates = model.structureShapes - .filter { it.defaultName().endsWith("Output") } .flatMap { it.allMembers.values } .filter { it.memberName == "Expires" } .map { diff --git a/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/customizations/S3ExpiresTest.kt b/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/customizations/S3ExpiresTest.kt index aefe609c70e..744ce94a812 100644 --- a/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/customizations/S3ExpiresTest.kt +++ b/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/customizations/S3ExpiresTest.kt @@ -35,18 +35,18 @@ class S3ExpiresTest { } @Test - fun `002 test S3 input members named expires are not changed`() { + fun `002 test S3 input members named expires are changed to string type`() { val context = setupTests("s3-expires.smithy", "com.amazonaws.s3#S3", "S3") val contents = TestUtils.getFileContents(context.manifest, "/Example/models/FooInput.swift") contents.shouldSyntacticSanityCheck() val expectedContents = """ public struct FooInput { - public var expires: ClientRuntime.Date? + public var expires: Swift.String? public var payload1: Swift.String? public init( - expires: ClientRuntime.Date? = nil, + expires: Swift.String? = nil, payload1: Swift.String? = nil ) {