diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 23e24360473..f5fa205ced1 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -46,12 +46,12 @@ jobs: - name: Select smithy-swift branch run: | ORIGINAL_REPO_HEAD_REF="$GITHUB_HEAD_REF" \ - DEPENDENCY_REPO_URL="https://github.com/awslabs/smithy-swift.git" \ + DEPENDENCY_REPO_URL="https://github.com/smithy-lang/smithy-swift.git" \ ./scripts/ci_steps/select_dependency_branch.sh - name: Checkout smithy-swift uses: actions/checkout@v3 with: - repository: awslabs/smithy-swift + repository: smithy-lang/smithy-swift ref: ${{ env.DEPENDENCY_REPO_SHA }} path: smithy-swift - name: Move smithy-swift into place @@ -113,12 +113,12 @@ jobs: - name: Select smithy-swift branch run: | ORIGINAL_REPO_HEAD_REF="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME:-main}}" \ - DEPENDENCY_REPO_URL="https://github.com/awslabs/smithy-swift.git" \ + DEPENDENCY_REPO_URL="https://github.com/smithy-lang/smithy-swift.git" \ ./scripts/ci_steps/select_dependency_branch.sh - name: Checkout smithy-swift uses: actions/checkout@v3 with: - repository: awslabs/smithy-swift + repository: smithy-lang/smithy-swift ref: ${{ env.DEPENDENCY_REPO_SHA }} path: smithy-swift - name: Move smithy-swift into place diff --git a/.github/workflows/model-integration.yml b/.github/workflows/model-integration.yml index 525eabad893..7ee77af2578 100644 --- a/.github/workflows/model-integration.yml +++ b/.github/workflows/model-integration.yml @@ -28,12 +28,12 @@ jobs: - name: Select smithy-swift branch run: | ORIGINAL_REPO_HEAD_REF="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME:-main}}" \ - DEPENDENCY_REPO_URL="https://github.com/awslabs/smithy-swift.git" \ + DEPENDENCY_REPO_URL="https://github.com/smithy-lang/smithy-swift.git" \ ./scripts/ci_steps/select_dependency_branch.sh - name: Checkout smithy-swift uses: actions/checkout@v3 with: - repository: awslabs/smithy-swift + repository: smithy-lang/smithy-swift ref: ${{ env.DEPENDENCY_REPO_SHA }} path: smithy-swift - name: Move smithy-swift into place diff --git a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/PrepareRelease.swift b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/PrepareRelease.swift index f65df9d38c0..9eceeae30f0 100644 --- a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/PrepareRelease.swift +++ b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Commands/PrepareRelease.swift @@ -20,7 +20,7 @@ struct PrepareReleaseCommand: ParsableCommand { @Argument(help: "The repository type to release. sdk or smithy-swift") var repoType: PrepareRelease.Repo - + @Argument(help: "The path to the git repository.") var repoPath: String @@ -28,8 +28,16 @@ struct PrepareReleaseCommand: ParsableCommand { var sourceCodeArtifactId: String func run() throws { + let repoOrg: PrepareRelease.Org + switch repoType { + case .awsSdkSwift: + repoOrg = .awslabs + case .smithySwift: + repoOrg = .smithyLang + } let prepareRelease = PrepareRelease.standard( repoType: repoType, + repoOrg: repoOrg, repoPath: repoPath, sourceCodeArtifactId: sourceCodeArtifactId ) @@ -45,10 +53,18 @@ struct PrepareRelease { case awsSdkSwift = "aws-sdk-swift" case smithySwift = "smithy-swift" } + + enum Org: String, ExpressibleByArgument { + case awslabs = "awslabs" + case smithyLang = "smithy-lang" + } /// The repository type to prepare the release /// This dictates which files are staged for commit let repoType: Repo + + /// The GitHub org that the repo belongs to + let repoOrg: Org /// The path to the package repository let repoPath: String @@ -174,6 +190,7 @@ struct PrepareRelease { let releaseNotes = ReleaseNotesBuilder( previousVersion: previousVersion, newVersion: newVersion, + repoOrg: repoOrg, repoType: repoType, commits: commits ).build() @@ -208,11 +225,13 @@ extension PrepareRelease { /// - Returns: The standard release preparer static func standard( repoType: Repo, + repoOrg: Org, repoPath: String, sourceCodeArtifactId: String ) -> Self { PrepareRelease( repoType: repoType, + repoOrg: repoOrg, repoPath: repoPath, sourceCodeArtifactId: sourceCodeArtifactId ) { branch, version in diff --git a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Models/ReleaseNotesBuilder.swift b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Models/ReleaseNotesBuilder.swift index 4f25ac3c0e0..e35ab256e14 100644 --- a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Models/ReleaseNotesBuilder.swift +++ b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Models/ReleaseNotesBuilder.swift @@ -12,6 +12,7 @@ import PackageDescription struct ReleaseNotesBuilder { let previousVersion: Version let newVersion: Version + let repoOrg: PrepareRelease.Org let repoType: PrepareRelease.Repo let commits: [String] @@ -22,7 +23,7 @@ struct ReleaseNotesBuilder { "## What's Changed", buildCommits(), .newline, - "**Full Changelog**: https://github.com/awslabs/\(repoType.rawValue)/compare/\(previousVersion)...\(newVersion)" + "**Full Changelog**: https://github.com/\(repoOrg.rawValue)/\(repoType.rawValue)/compare/\(previousVersion)...\(newVersion)" ] return contents.joined(separator: .newline) } diff --git a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Resources/Package.Base.swift b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Resources/Package.Base.swift index bd074f66c44..0fcd014b4b0 100644 --- a/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Resources/Package.Base.swift +++ b/AWSSDKSwiftCLI/Sources/AWSSDKSwiftCLI/Resources/Package.Base.swift @@ -56,7 +56,7 @@ func addDependencies(clientRuntimeVersion: Version, crtVersion: Version) { } func addClientRuntimeDependency(_ version: Version) { - let smithySwiftURL = "https://github.com/awslabs/smithy-swift" + let smithySwiftURL = "https://github.com/smithy-lang/smithy-swift" let useLocalDeps = ProcessInfo.processInfo.environment["AWS_SWIFT_SDK_USE_LOCAL_DEPS"] != nil let useMainDeps = ProcessInfo.processInfo.environment["AWS_SWIFT_SDK_USE_MAIN_DEPS"] != nil switch (useLocalDeps, useMainDeps) { diff --git a/AWSSDKSwiftCLI/Tests/AWSSDKSwiftCLITests/Commands/PrepareReleaseTests.swift b/AWSSDKSwiftCLI/Tests/AWSSDKSwiftCLITests/Commands/PrepareReleaseTests.swift index 86422f86593..0194adde89f 100644 --- a/AWSSDKSwiftCLI/Tests/AWSSDKSwiftCLITests/Commands/PrepareReleaseTests.swift +++ b/AWSSDKSwiftCLI/Tests/AWSSDKSwiftCLITests/Commands/PrepareReleaseTests.swift @@ -130,6 +130,7 @@ extension PrepareRelease { ) -> Self { PrepareRelease( repoType: repoType, + repoOrg: .awslabs, repoPath: repoPath, sourceCodeArtifactId: sourceCodeArtifactId, diffChecker: diffChecker diff --git a/IntegrationTests/Services/AWSECSIntegrationTests/ECSCredentialsProviderTests.swift b/IntegrationTests/Services/AWSECSIntegrationTests/ECSCredentialsProviderTests.swift new file mode 100644 index 00000000000..ac692673632 --- /dev/null +++ b/IntegrationTests/Services/AWSECSIntegrationTests/ECSCredentialsProviderTests.swift @@ -0,0 +1,330 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation +import XCTest +import AWSCloudWatchLogs +import AWSECS +import AWSEC2 +import AWSIAM +import AWSSTS +import ClientRuntime + +class ECSCredentialsProviderTests: XCTestCase { + + private let taskRoleName = "ecs_integ_test_task_role" + private let executionRoleName = "ecs_integ_test_execution_role" + private let clusterName = "ecs-integ-test-cluster" + private let taskFamilyName = "ecs-integ-test-family" + private let serviceName = "ecs-integ-test-service" + private let logGroupName = "/ecs/integ-test-group" + + private var taskRoleArn: String? = nil + private var executionRoleArn: String? = nil + private var networkingConfig: ECSClientTypes.NetworkConfiguration = ECSClientTypes.NetworkConfiguration() + private var taskDefArn: String = "" + + override func setUp() async throws { + try await setupIAMRolesAndPolicies() + try await setupCloudwatchLogs() + try await setupNetworkingConfig( + securityGroupNames: ["default"], + availabilityZones: ["us-east-1a", "us-east-1b"] + ) + } + + func test_ecsCredentialsProvider() async throws { + let ecsClient = try await ECSClient() + + // create cluster + let testCluster = try await ecsClient.createCluster(input: CreateClusterInput(clusterName: clusterName)) + guard let testClusterName = testCluster.cluster?.clusterName else { + XCTFail("Cluster could not be created!") + return + } + + // setup container + guard let accountId = try await getAccountId() else { + XCTFail("Couldn't retrieve account id from STS!") + return + } + let containerDefinition = getTestContainerDefinition(accountId: accountId) + + // register the task definition + let taskDefinition = getTestTaskDefinitionInput(container: containerDefinition) + guard let createdTaskArn = try await registerTaskDefinition(ecsClient, taskDefinition: taskDefinition) else { + XCTFail("Couldn't register task definition!") + return + } + taskDefArn = createdTaskArn + + // run the task directly without creating a service + let runTaskResp = try await ecsClient.runTask(input: RunTaskInput( + cluster: testClusterName, + count: 1, + launchType: .fargate, + networkConfiguration: networkingConfig, + taskDefinition: taskDefArn + )) + guard let tasks = runTaskResp.tasks, !tasks.isEmpty else { + XCTFail("Failed to run task") + return + } + + // there should only be one since we specified count: 1 + let taskArns = tasks.compactMap { $0.taskArn } + + // wait for task to complete, check every 30 seconds + try await waitForTaskToComplete(ecsClient, clusterName: testClusterName, tasks: taskArns, intervalSeconds: 30) + + // check logs for "Success!" + let logsContainKeyword = try await checkLogsForKeyword(keyword: "Success!") + XCTAssertTrue(logsContainKeyword, "Logs did not contain the expected keyword. Test failed!") + } + + override func tearDown() async throws { + // clean up resources + let ecsClient = try await ECSClient() + + // degregister task definition + _ = try await ecsClient.deregisterTaskDefinition(input: DeregisterTaskDefinitionInput( + taskDefinition: taskDefArn + )) + + // delete cluster + _ = try await ecsClient.deleteCluster(input: DeleteClusterInput( + cluster: clusterName + )) + } + + private func getAccountId() async throws -> String? { + let stsClient = try await STSClient() + let stsResp = try await stsClient.getCallerIdentity(input: GetCallerIdentityInput()) + return stsResp.account + } + + private func setupIAMRolesAndPolicies() async throws { + // Create IAM Role and Trust Policy + let iamClient = try await IAMClient() + + // create a trust policy and allows ecs to assume role + let trustPolicyJSON = """ + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] + } + """ + + taskRoleArn = try await createRole(iamClient, policy: trustPolicyJSON, roleName: taskRoleName) + + try await attachPolicy( + iamClient, + policyArn: "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", + roleName: taskRoleName + ) + + executionRoleArn = try await createRole(iamClient, policy: trustPolicyJSON, roleName: executionRoleName) + + try await attachPolicy( + iamClient, + policyArn: "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy", + roleName: executionRoleName + ) + } + + private func setupCloudwatchLogs() async throws { + // create cloudwatch log group if it doesn't exist + let logsClient = try await CloudWatchLogsClient() + let describeLogGroupsOutput = try await logsClient.describeLogGroups(input: DescribeLogGroupsInput( + logGroupNamePrefix: logGroupName + )) + if describeLogGroupsOutput.logGroups?.isEmpty ?? true { + _ = try await logsClient.createLogGroup(input: CreateLogGroupInput( + logGroupName: logGroupName + )) + print("Created log group \(logGroupName)") + } else { + print("Log group \(logGroupName) already exists") + } + } + + private func setupNetworkingConfig(securityGroupNames: [String], availabilityZones: [String]) async throws { + // create an ec2 client for getting security group and subnet + let ec2Client = try await EC2Client() + + // get default security group + let describeSecurityGroupsResp = try await ec2Client.describeSecurityGroups(input: DescribeSecurityGroupsInput( + groupNames: securityGroupNames + )) + guard let defaultSecurityGroupId = describeSecurityGroupsResp.securityGroups?.first?.groupId else { + XCTFail("Could not retrieve the default security group!") + return + } + + // get subnets + let describeSubnetsResponse = try await ec2Client.describeSubnets(input: DescribeSubnetsInput( + filters: [EC2ClientTypes.Filter(name: "availability-zone", values: availabilityZones)] + )) + guard let foundSubnets = describeSubnetsResponse.subnets else { + XCTFail("Could not retrieve subnets!") + return + } + let subnetIds = foundSubnets.compactMap { $0.subnetId } + + networkingConfig = ECSClientTypes.NetworkConfiguration( + awsvpcConfiguration: ECSClientTypes.AwsVpcConfiguration( + assignPublicIp: .enabled, + securityGroups: [defaultSecurityGroupId], + subnets: subnetIds + ) + ) + } + + private func getTestContainerDefinition(accountId: String) -> ECSClientTypes.ContainerDefinition { + // Create container def that points to ECR repo + return ECSClientTypes.ContainerDefinition( + cpu: 256, + image: "\(accountId).dkr.ecr.us-east-1.amazonaws.com/ecs-integ-test:latest", + logConfiguration: ECSClientTypes.LogConfiguration( + logDriver: .awslogs, + options: [ + "awslogs-group": logGroupName, + "awslogs-region": "us-east-1", + "awslogs-stream-prefix": "ecs" + ] + ), + memory: 512, + name: "ecs-integ-test-container" + ) + } + + private func getTestTaskDefinitionInput(container: ECSClientTypes.ContainerDefinition) -> RegisterTaskDefinitionInput { + return RegisterTaskDefinitionInput( + containerDefinitions: [container], + cpu: "256", + executionRoleArn: executionRoleArn, + family: taskFamilyName, + memory: "512", + networkMode: .awsvpc, + requiresCompatibilities: [.fargate], + runtimePlatform: ECSClientTypes.RuntimePlatform( + cpuArchitecture: ECSClientTypes.CPUArchitecture.arm64 + ), + taskRoleArn: taskRoleArn + ) + } + + private func registerTaskDefinition(_ ecsClient: ECSClient, taskDefinition: RegisterTaskDefinitionInput) async throws -> String? { + let registerTaskDefResp = try await ecsClient.registerTaskDefinition(input: taskDefinition) + return registerTaskDefResp.taskDefinition?.taskDefinitionArn + } + + private func getCreateServiceInput(clusterName: String, taskDefinitionArn: String) -> CreateServiceInput { + return CreateServiceInput( + cluster: clusterName, + desiredCount: 1, + launchType: .fargate, + networkConfiguration: networkingConfig, + serviceName: serviceName, + taskDefinition: taskDefinitionArn + ) + } + + private func createRole(_ iamClient: IAMClient, policy: String, roleName: String) async throws -> String? { + if let existingRoleArn = try await getRole(iamClient, roleName: roleName) { + return existingRoleArn + } + return try await createNewRole(iamClient, roleName: roleName, policy: policy) + } + + private func getRole(_ iamClient: IAMClient, roleName: String) async throws -> String? { + let fetchRoleResp = try await iamClient.getRole(input: GetRoleInput(roleName: roleName)) + return fetchRoleResp.role?.arn + } + + private func createNewRole(_ iamClient: IAMClient, roleName: String, policy: String) async throws -> String? { + let createRoleResp = try await iamClient.createRole(input: CreateRoleInput( + assumeRolePolicyDocument: policy, + roleName: roleName + )) + return createRoleResp.role?.arn + } + + private func attachPolicy(_ iamClient: IAMClient, policyArn: String, roleName: String) async throws { + do { + _ = try await iamClient.attachRolePolicy(input: AttachRolePolicyInput( + policyArn: policyArn, + roleName: roleName + )) + } catch { + print("Error occurred while attaching policy") + } + } + + private func waitForTaskToComplete(_ ecsClient: ECSClient, clusterName: String, tasks: [String], intervalSeconds: UInt64) async throws { + var isTaskCompleted = false + while !isTaskCompleted { + let describeTasksResp = try await ecsClient.describeTasks(input: DescribeTasksInput(cluster: clusterName, tasks: tasks)) + if let task = describeTasksResp.tasks?.first, task.lastStatus == "STOPPED" { + isTaskCompleted = true + } + try await Task.sleep(nanoseconds: intervalSeconds * 1_000_000_000) // Sleep for X seconds before retrying + } + } + + private func checkLogsForKeyword(keyword: String) async throws -> Bool { + let logsClient = try await CloudWatchLogsClient() + let logStreamsResp = try await logsClient.describeLogStreams(input: DescribeLogStreamsInput( + descending: true, + logGroupName: logGroupName, + orderBy: .lasteventtime + )) + + if let logStreamName = logStreamsResp.logStreams?.first?.logStreamName { + let logEventsResp = try await logsClient.getLogEvents(input: GetLogEventsInput( + logGroupName: logGroupName, + logStreamName: logStreamName + )) + + print("Log Group name: \(logGroupName)") + print("Log Stream name: \(logStreamName)") + + for event in logEventsResp.events ?? [] { + if let message = event.message, message.contains(keyword) { + return true + } + } + } + return false + } + + private func waitForServiceTasksToDrain(_ ecsClient: ECSClient, clusterName: String, serviceName: String, intervalSeconds: UInt64 = 10) async throws { + var allTasksStopped = false + while !allTasksStopped { + let serviceDescription = try await ecsClient.describeServices(input: DescribeServicesInput( + cluster: clusterName, + services: [serviceName] + )) + + if let service = serviceDescription.services?.first, service.runningCount == 0 { + allTasksStopped = true + } + + if !allTasksStopped { + try await Task.sleep(nanoseconds: intervalSeconds * 1_000_000_000) // Sleep for X seconds before retrying + } + } + } +} diff --git a/IntegrationTests/Services/AWSECSIntegrationTests/README.md b/IntegrationTests/Services/AWSECSIntegrationTests/README.md new file mode 100644 index 00000000000..45b9e533f88 --- /dev/null +++ b/IntegrationTests/Services/AWSECSIntegrationTests/README.md @@ -0,0 +1,8 @@ +# AWSECSIntegrationTests Description + +- ECSCredentialsProviderTests will launch all configuration needed to run a dockerized Swift package as a task inside of a Fargate ARM64 ECS cluster. +- The test will poll the task every X seconds (30) to see if it is completed. +- Upon task completion, the latest log stream will be scanned to look for keyword 'Success!' which the Swift program running inside of the cluster will emit if successful. +- ECS resources are cleaned up but cloudwatch logs and IAM roles remain so that the test can be re-run. +- Test should take ~3-5 minutes to run. +- See README.md inside of ECSIntegTestApp for further details. diff --git a/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Dockerfile b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Dockerfile new file mode 100644 index 00000000000..2d2735e050a --- /dev/null +++ b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Dockerfile @@ -0,0 +1,17 @@ +# Can also be set to a specific swift version like swift:5.7 +FROM swift:latest + +# Install dependencies to container +RUN apt-get update && apt-get install -y libssl-dev + +# Set our working directory +WORKDIR /app + +# Copy the entire Swift project into the Docker image +COPY . . + +# Build the swift application in release mode +RUN swift build --configuration release + +# Command to run the test application +CMD [".build/release/ECSIntegTestApp"] diff --git a/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Package.swift b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Package.swift new file mode 100644 index 00000000000..a4ed47cc02c --- /dev/null +++ b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Package.swift @@ -0,0 +1,26 @@ +// swift-tools-version: 5.5 + +import PackageDescription + +let package = Package( + name: "ECSIntegTestApp", + platforms: [ + .macOS(.v10_15), + .iOS(.v13) + ], + dependencies: [ + .package(url: "https://github.com/awslabs/aws-sdk-swift.git", branch: "main"), + .package(url: "https://github.com/smithy-lang/smithy-swift.git", branch: "main"), + .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.0.0"), + ], + targets: [ + .executableTarget( + name: "ECSIntegTestApp", + dependencies: [ + .product(name: "ArgumentParser", package: "swift-argument-parser"), + .product(name: "AWSSTS", package: "aws-sdk-swift"), + .product(name: "AWSClientRuntime", package: "aws-sdk-swift"), + ] + ) + ] +) diff --git a/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/README.md b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/README.md new file mode 100644 index 00000000000..7c5d2da2581 --- /dev/null +++ b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/README.md @@ -0,0 +1,12 @@ +## ECS Integration Testing + +This package will be used to test aws-sdk-swift and AWS ECS. The below steps will need to be excuted prior to running the integration test. The contents of this package are executed inside of an ECS cluster. + +Note: `./deploy-docker-to-ecr` only needs to be executed once per AWS account and if updates are needed to the underlying package versions or test run inside ECS container + +How to use `./deploy-docker-to-ecr`: +- Make sure you have permissions configured using aws configure and docker daemon running +- `chmod +x deploy-docker-to-ecr.sh` +- `./deploy-docker-to-ecr.sh 123456789012` or `./deploy-docker-to-ecr.sh 123456789012 us-west-2` or `./deploy-docker-to-ecr.sh 123456789012 us-west-2 my-repo-name` +- if login window pops up, login using either your aws username/password or temporary access credentials and write `exit` upon successful login (bug) + diff --git a/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Sources/ECSIntegTestApp/main.swift b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Sources/ECSIntegTestApp/main.swift new file mode 100644 index 00000000000..ea354fc0e17 --- /dev/null +++ b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/Sources/ECSIntegTestApp/main.swift @@ -0,0 +1,30 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation +import AWSClientRuntime +import AWSSTS + +func executeSTSTask() async throws { + let clientConfig = try await STSClient.STSClientConfiguration( + credentialsProvider: ECSCredentialsProvider() + ) + let client = STSClient(config: clientConfig) + let response = try await client.getCallerIdentity(input: GetCallerIdentityInput()) + + print("Account: \(response.account ?? "No account found!")") + print("Arn: \(response.arn ?? "No arn found!")") + print("UserId: \(response.userId ?? "No userId found!")") + + if response.account != nil && response.arn != nil && response.userId != nil { + print("Success!") + } +} + +print("Starting task execution...") +try await executeSTSTask() +print("Task completed.") diff --git a/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/deploy-docker-to-ecr.sh b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/deploy-docker-to-ecr.sh new file mode 100755 index 00000000000..0c585861be0 --- /dev/null +++ b/IntegrationTests/Services/AWSECSIntegrationTests/Resources/ECSIntegTestApp/deploy-docker-to-ecr.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Script will stop executing on first error +set -e + +# Take in arguments from command line: account_id (required), region (optional), and repo_name (optional) +if [ "$#" -lt 1 ]; then + echo "Usage: $0 [REGION] [REPO_NAME]" + exit 1 +fi + +# Assign variables +REGION="${2:-us-east-1}" # default value of us-east-1 +REPO_NAME="${3:-ecs-integ-test}" # default value of ecs-integ-test +ACCOUNT_ID="$1" +ECR_URI="$ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com" + +echo "Using region: $REGION, repo_name: $REPO_NAME, and account_id: $ACCOUNT_ID" + +# Authenticate +$(aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_URI) + +# Check if ECR repo exists +REPO_EXISTS=$(aws ecr describe-repositories --repository-names $REPO_NAME --region $REGION 2>&1 || true) + +if [[ $REPO_EXISTS == *"repository not found"* ]]; then + echo "Creating repository named $REPO_NAME..." + aws ecr create-repository --repository-name $REPO_NAME --region $REGION + echo "Repository $REPO_NAME created successfully" +fi + +# Build docker image +docker build -t $REPO_NAME . + +# Tag the docker image for versioning +docker tag $REPO_NAME:latest $ECR_URI/$REPO_NAME:latest + +# Push to ECR +docker push $ECR_URI/$REPO_NAME:latest + +echo "Docker image pushed to ECR successfully" diff --git a/Package.swift b/Package.swift index da9efce0cfe..f39ee057483 100644 --- a/Package.swift +++ b/Package.swift @@ -56,7 +56,7 @@ func addDependencies(clientRuntimeVersion: Version, crtVersion: Version) { } func addClientRuntimeDependency(_ version: Version) { - let smithySwiftURL = "https://github.com/awslabs/smithy-swift" + let smithySwiftURL = "https://github.com/smithy-lang/smithy-swift" let useLocalDeps = ProcessInfo.processInfo.environment["AWS_SWIFT_SDK_USE_LOCAL_DEPS"] != nil let useMainDeps = ProcessInfo.processInfo.environment["AWS_SWIFT_SDK_USE_MAIN_DEPS"] != nil switch (useLocalDeps, useMainDeps) { @@ -106,11 +106,24 @@ func addServiceTarget(_ name: String) { func addIntegrationTestTarget(_ name: String) { let integrationTestName = "\(name)IntegrationTests" + var additionalDependencies: [PackageDescription.Target.Dependency] = [] + var exclusions: [String] = [] + switch name { + case "AWSECS": + additionalDependencies = ["AWSCloudWatchLogs", "AWSEC2", "AWSIAM"] + exclusions = [ + "README.md", + "Resources/ECSIntegTestApp/" + ] + default: + break + } package.targets += [ .testTarget( name: integrationTestName, - dependencies: [.crt, .clientRuntime, .awsClientRuntime, .byName(name: name), .smithyTestUtils], + dependencies: [.crt, .clientRuntime, .awsClientRuntime, .byName(name: name), .smithyTestUtils] + additionalDependencies, path: "./IntegrationTests/Services/\(integrationTestName)", + exclude: exclusions, resources: [.process("Resources")] ) ] @@ -536,4 +549,4 @@ let servicesWithIntegrationTests: [String] = [ servicesWithIntegrationTests.forEach(addIntegrationTestTarget) // Uncomment this line to enable protocol tests -// addProtocolTests() \ No newline at end of file +// addProtocolTests() diff --git a/Sources/Core/AWSClientRuntime/Auth/CredentialsProviders/ECSCredentialsProvider.swift b/Sources/Core/AWSClientRuntime/Auth/CredentialsProviders/ECSCredentialsProvider.swift new file mode 100644 index 00000000000..53658b2e673 --- /dev/null +++ b/Sources/Core/AWSClientRuntime/Auth/CredentialsProviders/ECSCredentialsProvider.swift @@ -0,0 +1,84 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import AwsCommonRuntimeKit +import ClientRuntime +import Foundation + +/// A credentials provider that sources credentials from ECS container metadata +public struct ECSCredentialsProvider: CredentialsSourcedByCRT { + let crtCredentialsProvider: CRTCredentialsProvider + /// Creates a credential provider that sources credentials from ECS container metadata + /// ECS creds provider can be used to access creds via either relative uri to a fixed endpoint http://169.254.170.2, + /// or via a full uri specified by environment variables: + /// - AWS_CONTAINER_CREDENTIALS_RELATIVE_URI + /// - AWS_CONTAINER_CREDENTIALS_FULL_URI + /// - AWS_CONTAINER_AUTHORIZATION_TOKEN + /// + /// If both relative uri and absolute uri are set, relative uri has higher priority. + /// Token is used in auth header but only for absolute uri. + /// - Returns: `CredentialsProvider` + /// - Throws: CommonRuntimeError.crtError or InitializationError.missingURIs + public init( + relativeURI: String? = nil, + absoluteURI: String? = nil, + authorizationToken: String? = nil + ) throws { + let env = ProcessEnvironment() + + let resolvedRelativeURI = relativeURI ?? env.environmentVariable(key: "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") + let resolvedAbsoluteURI = absoluteURI ?? env.environmentVariable(key: "AWS_CONTAINER_CREDENTIALS_FULL_URI") + + guard resolvedRelativeURI != nil || isValidAbsoluteURI(resolvedAbsoluteURI) else { + throw ClientError.dataNotFound( + "Please configure either the relative or absolute URI environment variable!" + ) + } + + let defaultHost = "169.254.170.2" + var host = defaultHost + var pathAndQuery = resolvedRelativeURI ?? "" + + if let relative = resolvedRelativeURI { + pathAndQuery = relative + } else if let absolute = resolvedAbsoluteURI, let absoluteURL = URL(string: absolute) { + let (absoluteHost, absolutePathAndQuery) = try retrieveHostPathAndQuery(from: absoluteURL) + host = absoluteHost + pathAndQuery = absolutePathAndQuery + } else { + throw ClientError.pathCreationFailed("Failed to retrieve either relative or absolute URI! URI may be malformed.") + } + + self.crtCredentialsProvider = try CRTCredentialsProvider(source: .ecs( + bootstrap: SDKDefaultIO.shared.clientBootstrap, + pathAndQuery: pathAndQuery, + host: host + )) + } +} + +private func retrieveHostPathAndQuery(from url: URL) throws -> (String, String) { + guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { + throw ClientError.pathCreationFailed("Absolute URI is malformed! Could not instantiate URLComponents from URL.") + } + guard let hostComponent = components.host else { + throw ClientError.pathCreationFailed("Absolute URI is malformed! Could not retrieve host from URL.") + } + components.scheme = nil + components.host = nil + guard let pathQueryFragment = components.url else { + throw ClientError.pathCreationFailed("Could not retrieve path from URL!") + } + return (hostComponent, pathQueryFragment.absoluteString) +} + +private func isValidAbsoluteURI(_ uri: String?) -> Bool { + guard let validUri = uri, let _ = URL(string: validUri)?.host else { + return false + } + return true +} diff --git a/THIRD-PARTY-LICENSES b/THIRD-PARTY-LICENSES index 75fa0998315..94288d78179 100644 --- a/THIRD-PARTY-LICENSES +++ b/THIRD-PARTY-LICENSES @@ -216,9 +216,9 @@ Licensed under Apache License v2.0 with Runtime Library Exception ------ -** aws-crt-swift; version 0.2.2 -- https://github.com/awslabs/aws-crt-swift +** aws-crt-swift -- https://github.com/awslabs/aws-crt-swift Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -** smithy-swift; version 0.2.4 -- https://github.com/awslabs/smithy-swift +** smithy-swift -- https://github.com/smithy-lang/smithy-swift Smithy Swift Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/Tests/Core/AWSClientRuntimeTests/Auth/CredentialsProvidersTests/ECSCredentialsProviderTests.swift b/Tests/Core/AWSClientRuntimeTests/Auth/CredentialsProvidersTests/ECSCredentialsProviderTests.swift new file mode 100644 index 00000000000..5f2080097cd --- /dev/null +++ b/Tests/Core/AWSClientRuntimeTests/Auth/CredentialsProvidersTests/ECSCredentialsProviderTests.swift @@ -0,0 +1,84 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import ClientRuntime +import Foundation +import XCTest + +@_spi(FileBasedConfig) @testable import AWSClientRuntime + +class ECSCredentialsProviderTests: XCTestCase { + func testGetCredentialsWithRelativeURI() async throws { + // relative uri is preferred over absolute uri so we shouldn't get thrown an error + XCTAssertNoThrow(try ECSCredentialsProvider(relativeURI: "subfolder/test.txt", absoluteURI: "invalid absolute uri")) + } + + func testGetCredentialsWithAbsoluteURI() async throws { + XCTAssertNoThrow(try ECSCredentialsProvider(relativeURI: nil, absoluteURI: "http://www.example.com/subfolder/test.txt")) + } + + func testGetCredentialsWithInvalidAbsoluteURI() async throws { + XCTAssertThrowsError(try ECSCredentialsProvider(relativeURI: nil, absoluteURI: "test")) + } + + func testGetCredentialsWithMissingURI() async throws { + XCTAssertThrowsError(try ECSCredentialsProvider(relativeURI: nil, absoluteURI: nil)) + } + + func testGetCredentialsWithRelativeURIEnv() async throws { + // relative uri is preferred over absolute uri so we shouldn't get thrown an error + setenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "subfolder/test.txt", 1) + unsetenv("AWS_CONTAINER_CREDENTIALS_FULL_URI") + XCTAssertNoThrow(try ECSCredentialsProvider()) + } + + func testGetCredentialsWithAbsoluteURIEnv() async throws { + unsetenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") + setenv("AWS_CONTAINER_CREDENTIALS_FULL_URI", "http://www.example.com/subfolder/test.txt", 1) + XCTAssertNoThrow(try ECSCredentialsProvider()) + } + + func testGetCredentialsWithInvalidAbsoluteURIEnv() async throws { + unsetenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") + setenv("AWS_CONTAINER_CREDENTIALS_FULL_URI", "test", 1) + XCTAssertThrowsError(try ECSCredentialsProvider()) + } + + func testGetCredentialsWithMissingURIEnv() async throws { + unsetenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") + unsetenv("AWS_CONTAINER_CREDENTIALS_FULL_URI") + XCTAssertThrowsError(try ECSCredentialsProvider()) + } +} + +protocol EnvironmentProvider { + func environmentVariable(key: String) -> String? +} + +class MockEnvironment: Environment, EnvironmentProvider { + let relativeURI: String? + let absoluteURI: String? + + init( + relativeURI: String? = nil, + absoluteURI: String? = nil + ) { + self.relativeURI = relativeURI + self.absoluteURI = absoluteURI + } + + func environmentVariable(key: String) -> String? { + switch key { + case "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI": + return self.relativeURI + case "AWS_CONTAINER_CREDENTIALS_FULL_URI": + return self.absoluteURI + default: + return nil + } + } +} diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSServiceUtils.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSServiceUtils.kt index a194acc0d38..a0c6997d0f9 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSServiceUtils.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/AWSServiceUtils.kt @@ -10,20 +10,20 @@ import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.swift.codegen.model.expectTrait /** - * Get the [sdkId](https://awslabs.github.io/smithy/1.0/spec/aws/aws-core.html#sdkid) from the (AWS) service shape + * Get the [sdkId](https://smithy.io/2.0/aws/aws-core.html#sdkid) from the (AWS) service shape */ val ServiceShape.sdkId: String get() = expectTrait().sdkId /** - * Get the [arnNamespace](https://awslabs.github.io/smithy/1.0/spec/aws/aws-core.html#service-arn-namespace) + * Get the [arnNamespace](https://smithy.io/2.0/aws/aws-core.html#arnnamespace) * from the (AWS) service shape */ val ServiceShape.arnNamespace: String get() = expectTrait().arnNamespace /** - * Get the [endpointPrefix](https://awslabs.github.io/smithy/1.0/spec/aws/aws-core.html#endpointprefix) + * Get the [endpointPrefix](https://smithy.io/2.0/aws/aws-core.html#endpointprefix) * from the (AWS) service shape */ val ServiceShape.endpointPrefix: String diff --git a/scripts/buildswiftsdk.sh b/scripts/buildswiftsdk.sh deleted file mode 100755 index 7a08304d81a..00000000000 --- a/scripts/buildswiftsdk.sh +++ /dev/null @@ -1,348 +0,0 @@ -#!/bin/bash - -# Pre-requisite: -# - Clone the following github repositories to a __single directory__: -# mkdir ~/Projects/SwiftSDK -# cd ~/Projects/SwiftSDK -# git clone git@github.com:awslabs/aws-sdk-swift.git -# git clone git@github.com:awslabs/smithy-swift.git -# git clone --recurse-submodules git@github.com:awslabs/aws-crt-swift.git -# -# Setup Instructions: -# 1. Ensure buildswiftsdk.sh is in your PATH -# 2. Export the environment variable BUILDSWIFTSDK_DIR to point to where you cloned aws-sdk-swift -# For example: -# emacs ~/.bashrc -# export BUILDSWIFTSDK_DIR=/path/to/aws-sdk-swift -# -# Run: -# buildswiftsdk.sh -# -# Suggestion: -# You may want to create an alias for this script -# For example: -# alias bss=buildswiftsdk.sh -# - -usage() { - echo "Usage:" - echo " buildswiftsdk " -} - -pushdir() { - if [[ ! -d "${1}" ]]; then - echo "Error: pushdir: invalid directory: ${1}" - exit 1 - fi - pushd "${1}" > /dev/null 2>&1 -} - -popdir() { - popd > /dev/null 2>&1 -} - -RETURNVAL= -dereference() { - local VAR=$1 - if [[ $IS_ZSH -eq 1 ]]; then - RETURNVAL="${(P)VAR}" - else - RETURNVAL="${!VAR}" - fi -} - -setupPaths() { - pushdir "${AWS_SDK_SWIFT_DIR_REL}" - AWS_SDK_SWIFT_DIR="${PWD}" - SMITHY_SWIFT_DIR_REL="${PWD}/../smithy-swift" - if [[ -d "${SMITHY_SWIFT_DIR_REL}" ]]; then - pushdir "${SMITHY_SWIFT_DIR_REL}" - SMITHY_SWIFT_DIR="${PWD}" - popdir - fi - CLIENT_RUNTIME_DIR="${SMITHY_SWIFT_DIR}/Packages" - AWS_CLIENT_RUNTIME_DIR="${AWS_SDK_SWIFT_DIR}/AWSClientRuntime" - popdir - BASEPCG="${AWS_SDK_SWIFT_DIR}/codegen/protocol-test-codegen/build/smithyprojections/protocol-test-codegen" - BASEPCGL="${AWS_SDK_SWIFT_DIR}/codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local" - REST_JSON="${BASEPCG}/aws-restjson/swift-codegen" - AWSJSON10="${BASEPCG}/aws-json-10/swift-codegen" - AWSJSON11="${BASEPCG}/aws-json-11/swift-codegen" - REST_XML="${BASEPCG}/rest-xml/swift-codegen" - AWSQUERY="${BASEPCG}/aws-query/swift-codegen" - EC2QUERY="${BASEPCG}/ec2-query/swift-codegen" -} - -checkPaths() { - error=0 - if [[ ! -d "${SMITHY_SWIFT_DIR}" ]]; then - echo "Was unable to detect smithy-swift" - error=1 - fi - if [[ ! -d "${AWS_SDK_SWIFT_DIR}" ]]; then - echo "Was unable to detect where aws-sdk-swift" - error=1 - fi - if [[ ${error} -eq 1 ]]; then - exit 1 - fi -} -SWIFTLINT= -swiftlintSetup() { - SWIFTLINT=`which swiftlint` -} - -AWS_SDK_SWIFT_DIR="" -SMITHY_SWIFT_DIR="" -BASEPCG="" -if [[ -z "${BUILDSWIFTSDK_DIR}" ]]; then - AWS_SDK_SWIFT_DIR_REL=`dirname ${0}`/../ -else - AWS_SDK_SWIFT_DIR_REL="${BUILDSWIFTSDK_DIR}" -fi -setupPaths -checkPaths -swiftlintSetup - - -checkReturn() { - if [ $1 -ne 0 ]; then - echo "" - echo $2 - exit 1 - fi -} - -buildall() { - cd "${SMITHY_SWIFT_DIR}" && ./gradlew build - checkReturn $? "Failed on: ./gradlew build in ${SMITHY_SWIFT_DIR}" - cd "${SMITHY_SWIFT_DIR}/Packages" && swift test - checkReturn $? "Failed on: swift test in ${SMITHY_SWIFT_DIR}/Packages" - cd "${AWS_SDK_SWIFT_DIR}" && ./gradlew build - checkReturn $? "Failed on: ./gradlew build in ${AWS_SDK_SWIFT_DIR}" - cd "${CLIENT_RUNTIME_DIR}" && swift test - checkReturn $? "Failed on: swift test in ${CLIENT_RUNTIME_DIR}" - cd "${AWS_CLIENT_RUNTIME_DIR}" && swift test - checkReturn $? "Failed on: swift test in ${AWS_CLIENT_RUNTIME_DIR}" - cd "${AWS_SDK_SWIFT_DIR}/codegen" && swift test - checkReturn $? "Failed on: swift test in codegen" -} - - -pcg() { - cd "${SMITHY_SWIFT_DIR}" && \ - ./gradlew -p smithy-swift-codegen assemble && \ - cd "${AWS_SDK_SWIFT_DIR}" && \ - ./gradlew -p codegen/protocol-test-codegen clean &&\ - ./gradlew -p codegen/protocol-test-codegen-local clean &&\ - ./gradlew -p codegen/protocol-test-codegen build && - ./gradlew -p codegen/protocol-test-codegen-local build - echo "Generated files should be in both:" - echo "${BASEPCG}" - echo "${BASEPCGL}" -} - -rpcg() { - if [ -z $1 ]; then - RUNDIRS="${AWS_SDK_SWIFT_DIR}/codegen" - elif [ x$1 == x"rj" ]; then - RUNDIRS="${REST_JSON}" - elif [ x$1 == x"10" ]; then - RUNDIRS="${AWSJSON10}" - elif [ x$1 == x"11" ]; then - RUNDIRS="${AWSJSON11}" - elif [ x$1 == x"rx" ]; then - RUNDIRS="${REST_XML}" - elif [ x$1 == x"aq" ]; then - RUNDIRS="${AWSQUERY}" - elif [ x$1 == x"e2" ]; then - RUNDIRS="${EC2QUERY}" - fi - - FAILEDDIRS="" - for codegendir in ${RUNDIRS}; do - echo "entering: ${codegendir}" - cd ${codegendir} && swift test - RETVAL=$? - if [ $RETVAL -ne 0 ]; then - temp="${FAILEDDIRS} ${codegendir}" - FAILEDDIRS="${temp}" - fi - done - - ATTEMPTED_DISPLAYDIRS_ABS=`echo ${RUNDIRS}|tr ' ' '\n'` - ATTEMPTED_DISPLAYDIRS=`echo ${RUNDIRS}|tr ' ' '\n' |sed "s/.*protocol-test-codegen\/\(.*\)\/swift-codegen/\1/g"` - FAILED_DISPLAYDIRS=`echo ${FAILEDDIRS}|tr ' ' '\n' |sed "s/.*protocol-test-codegen\/\(.*\)\/swift-codegen/\1/g"` - - echo "" - echo "" - echo "SUMMARY:" - echo "" - echo "Attempted (Absolute Path):" - echo "${ATTEMPTED_DISPLAYDIRS_ABS}" - echo "" - echo "Attempted (friendly names):" - echo "${ATTEMPTED_DISPLAYDIRS}" - echo "" - if [[ x"${FAILEDDIRS}" != x"" ]]; then - echo "FAILED for:" - echo "${FAILED_DISPLAYDIRS}" - else - echo "SUCCESS!" - fi -} - -SDK_cognito=cognito-identity.2014-06-30 -SDK_lambda=lambda.2015-03-31 -SDK_s3=s3.2006-03-01 -SDK_swf=swf.2012-01-25 -SDK_ssm=ssm-incidents.2018-05-10 -sdk() { - SDKREF=$1 - SDK_POINTER="SDK_${SDKREF}" - dereference "${SDK_POINTER}" - SDK_ONLY="${RETURNVAL}" - - if [[ ! -z "${SDK_ONLY}" ]]; then - PROPFILE=${AWS_SDK_SWIFT_DIR}/local.properties - cat "${PROPFILE}" | grep -e "^onlyIncludeModels" | tail -1 | grep -e "^onlyIncludeModels=${SDK_ONLY}" > /dev/null 2>&1 - if [ $? -ne 0 ]; then - cat "${PROPFILE}" | grep -e "^onlyIncludeModels" > /dev/null 2>&1 - HAS_INCLUDE_MODELS=$? - LOCAL_PROPS_FILE="${AWS_SDK_SWIFT_DIR}/local.properties" - if [ ${HAS_INCLUDE_MODELS} -eq 0 ]; then - LOCALTEMP=/tmp/.buildswiftsdktemp - sed "s/^onlyIncludeModels=.*/onlyIncludeModels=${SDK_ONLY}/g" "${LOCAL_PROPS_FILE}" > ${LOCALTEMP} - echo "" >> ${LOCALTEMP} - SUFFIX=`date "+%Y%m%d%H%M%S"` - mv "${LOCAL_PROPS_FILE}" "${LOCAL_PROPS_FILE}.${SUFFIX}" - mv "${LOCALTEMP}" "${LOCAL_PROPS_FILE}" - else - echo "onlyIncludeModels=${SDK_ONLY}" >> ${LOCAL_PROPS_FILE} - echo "" >> ${LOCAL_PROPS_FILE} - fi - fi - fi - - cd "${AWS_SDK_SWIFT_DIR}" && \ - ./gradlew -p codegen/sdk-codegen build - - CODEGEN_OUTPUT_DIR="${AWS_SDK_SWIFT_DIR}/codegen/sdk-codegen/build/smithyprojections/sdk-codegen" - SDK_OUTPUT=`ls ${CODEGEN_OUTPUT_DIR} |grep -v "source"` - if [ ! -z "${SDK_OUTPUT}" ]; then - echo "Artifacts folder(s):" - for sdk in ${SDK_OUTPUT}; do - echo "${CODEGEN_OUTPUT_DIR}/${sdk}/swift-codegen" - done - else - echo "Build folder:" - echo "${CODEGEN_OUTPUT_DIR}" - fi - link -} - -link() { - PROJ_DIR="${AWS_SDK_SWIFT_DIR}/codegen/sdk-codegen/build/smithyprojections/sdk-codegen" - PROJECTIONS=`ls ${PROJ_DIR}|grep -v source` - for projection in ${PROJECTIONS}; do - projName=`echo ${projection} | tr '.' ' '| awk '{print $1}'` - cd ${PROJ_DIR}/${projection} && ln -vs swift-codegen ${projName} - done -} - -lint() { - klint - slint -} - -klint() { - cd "${AWS_SDK_SWIFT_DIR}" && \ - ./gradlew ktlintFormat - cd "${SMITHY_SWIFT_DIR}" && \ - ./gradlew ktlintFormat -} - -slint() { - if [[ ! -z "${SWIFTLINT}" ]]; then - cd "${AWS_CLIENT_RUNTIME_DIR}" && "${SWIFTLINT}" autocorrect - cd "${CLIENT_RUNTIME_DIR}" && "${SWIFTLINT}" autocorrect - else - echo "swiftlint not installed, skipping" - fi -} - -ssclean() { - cd "${SMITHY_SWIFT_DIR}" && \ - ./gradlew clean -} - -sdkclean() { - cd "${AWS_SDK_SWIFT_DIR}" && \ - ./gradlew clean -} - -clean() { - ssclean && sdkclean -} - -checkIfServiceDefined() { - SDKREF=$1 - SDK_POINTER="SDK_${SDKREF}" - dereference "${SDK_POINTER}" - SDK_ONLY="${RETURNVAL}" - if [ x"" != x"${SDK_ONLY}" ]; then - RETURNVAL=0 - else - RETURNVAL=1 - fi - -} - -interpretArgs() { - case "$1" in - "b") - buildall - ;; - "pcg") - pcg - ;; - "rpcg") - rpcg $2 - ;; - "clean") - clean - ;; - "sdk") - sdk $2 - ;; - "link") - link - ;; - "lint") - lint - ;; - "klint") - klint - ;; - "slint") - slint - ;; - "ssclean") - ssclean - ;; - "sdkclean") - sdkclean - ;; - *) - usage - ;; - esac -} - -checkIfServiceDefined $1 -if [ ${RETURNVAL} -eq 0 ]; then - sdk $1 -else - interpretArgs $* -fi - diff --git a/scripts/updateReleaseToLocalDev.sh b/scripts/updateReleaseToLocalDev.sh deleted file mode 100755 index ad36c53902d..00000000000 --- a/scripts/updateReleaseToLocalDev.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash - -# Use this script after pulling down a local copy of the AWS Swift SDK to your local machine. -# Doing so will allow you to build (and modify) a local copy of the AWS Swift SDK. -# -# After setting this up, you can update your executable's Package.swift to depend on a local version of the SDK via: -# -# dependencies: [ -# .package(name: "AWSSwiftSDK", path:"~/Projects/SwiftSDK_Releases/aws-sdk-swift"), -# ], - -# -# Setup Instructions -# Note: Versions listed below should be updated to your preference (ideally, the latest) -# -# mkdir -p ~/Projects/SwiftSDK_Releases -# cd ~/Projects/SwiftSDK_Releases -# -# git clone git@github.com:awslabs/aws-sdk-swift.git -# cd aws-sdk-swift -# git checkout -b 0.1.1 -# cd .. -# -# git clone git@github.com:awslabs/smithy-swift.git -# cd smithy-swift -# git checkout -b 0.1.1 -# cd .. -# -# git clone --recurse-submodules git@github.com:awslabs/aws-crt-swift.git -# cd aws-crt-swift -# git checkout -b 0.1.0 -# cd .. -# -# ./aws-sdk-swift/scripts/updateReleaseToLocalDev.sh -# -# If this script runs successfully, you can depend on a local version of the SDK - - -AWS_SDK_SWIFT= -SMITHY_SWIFT= -AWS_CRT_SWIFT= - -determineAbsolutePath() { - SCRIPTDIR=`dirname $1` - pushd ${SCRIPTDIR} > /dev/null - cd ../../ - AWS_SDK_SWIFT=$PWD/aws-sdk-swift - SMITHY_SWIFT=$PWD/smithy-swift - AWS_CRT_SWIFT=$PWD/aws-crt-swift -} - -determineAbsolutePath $0 - -if [ -z ${AWS_SDK_SWIFT} ] || [ ! -d ${AWS_SDK_SWIFT} ]; then - echo "Unable to detect aws-sdk-swift" - exit 1 -fi - -if [ -z ${SMITHY_SWIFT} ] || [ ! -d ${SMITHY_SWIFT} ]; then - echo "Unable to detect smithy-swift" - exit 1 -fi - -if [ -z ${AWS_CRT_SWIFT} ] || [ ! -d ${AWS_CRT_SWIFT} ]; then - echo "Unable to detect aws-crt-swift" - exit 1 -fi - -TEMPFILE=`mktemp` -AWS_SDK_SWIFT_PACKAGE=${AWS_SDK_SWIFT}/Package.swift -cat ${AWS_SDK_SWIFT_PACKAGE} |\ - sed -e "s|\(.*\)url:\ \"https://github.com/awslabs/aws-crt-swift.*\"\(.*\)|\1path:\ \"$AWS_CRT_SWIFT\"\2|g" \ - -e "s|\(.*\)url:\ \"https://github.com/awslabs/smithy-swift.*\"\(.*\)|\1path:\ \"$SMITHY_SWIFT\"\2|g" > ${TEMPFILE} -mv ${TEMPFILE} ${AWS_SDK_SWIFT_PACKAGE} -rm -f ${TEMPFILE} -# Package.swift in 'AWSClientRuntime' needs to be removed if users are depending on the top level Package.swift to easily browse code in XCode -rm -f ${AWS_SDK_SWIFT}/AWSClientRuntime/Package.swift -echo "Updated ${AWS_SDK_SWIFT_PACKAGE}" - -TEMPFILE=`mktemp` -SMITHY_SWIFT_PACKAGE=${SMITHY_SWIFT}/Package.swift -cat ${SMITHY_SWIFT_PACKAGE} |\ - sed -e "s|\(.*\)url:\ \"https://github.com/awslabs/aws-crt-swift.*\"\(.*\)|\1path:\ \"$AWS_CRT_SWIFT\"\2|g" > ${TEMPFILE} -mv ${TEMPFILE} ${SMITHY_SWIFT_PACKAGE} -rm -f ${TEMPFILE} -# Package.swift in 'Packages' needs to be removed if users are depending on the top level Package.swift to easily browse code in XCode -rm -f ${SMITHY_SWIFT}/Packages/Package.swift -echo "Updated ${SMITHY_SWIFT_PACKAGE}"