diff --git a/.github/workflows/cd-cdk.yaml b/.github/workflows/cd-cdk.yaml index 2aed4c6..f443af2 100644 --- a/.github/workflows/cd-cdk.yaml +++ b/.github/workflows/cd-cdk.yaml @@ -11,6 +11,14 @@ on: description: "Python version for Python CDK repos (leave empty for TypeScript CDK)" type: string default: "" + dotnet-version: + description: "Optional .NET SDK version for repos with .NET assets" + type: string + default: "" + dotnet-publish-project: + description: "Optional .NET project path to publish before CDK deploy" + type: string + default: "" region: description: "AWS region" type: string @@ -27,6 +35,10 @@ on: description: "CloudFormation stack name (for pre-flight checks)" type: string default: "" + post-deploy-script: + description: "Optional path to a script to run after CDK deploy (e.g. web build, S3 sync)" + type: string + default: "" secrets: deploy-role-arn: description: "OIDC deploy role ARN" @@ -46,6 +58,15 @@ jobs: - uses: docker/setup-qemu-action@v3 if: ${{ inputs.enable-qemu }} + - uses: actions/setup-dotnet@v5 + if: ${{ inputs.dotnet-version != '' }} + with: + dotnet-version: ${{ inputs.dotnet-version }} + + - name: Publish .NET project + if: ${{ inputs.dotnet-publish-project != '' }} + run: dotnet publish ${{ inputs.dotnet-publish-project }} --configuration Release --runtime linux-arm64 --self-contained false --output $(dirname ${{ inputs.dotnet-publish-project }})/bin/Release/net8.0/linux-arm64/publish + - uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} @@ -56,7 +77,7 @@ jobs: python-version: ${{ inputs.python-version }} - name: Install Node dependencies - if: ${{ inputs.python-version == '' }} + working-directory: ${{ inputs.cdk-dir }} run: npm ci - name: Install Python dependencies @@ -99,6 +120,10 @@ jobs: working-directory: ${{ inputs.cdk-dir }} run: npx -y cdk deploy --all --require-approval never + - name: Post-deploy script + if: ${{ inputs.post-deploy-script != '' }} + run: bash ${{ inputs.post-deploy-script }} + - name: Post-deploy health check if: ${{ inputs.stack-name != '' }} run: | diff --git a/.github/workflows/cd-mobile-ios.yaml b/.github/workflows/cd-mobile-ios.yaml new file mode 100644 index 0000000..845d3f6 --- /dev/null +++ b/.github/workflows/cd-mobile-ios.yaml @@ -0,0 +1,94 @@ +name: CD — Mobile iOS (TestFlight) + +on: + workflow_call: + inputs: + node-version: + description: "Node.js version to use" + type: string + default: "24" + ruby-version: + description: "Ruby version for Fastlane" + type: string + default: "3.3" + working-directory: + description: "Directory containing the mobile project" + type: string + default: "." + cache-dependency-path: + description: "Path to package-lock.json for npm cache" + type: string + default: "package-lock.json" + fastlane-lane: + description: "Fastlane lane to run" + type: string + default: "ios beta" + region: + description: "AWS region (for match S3 storage)" + type: string + default: "us-east-1" + timeout-minutes: + description: "Job timeout in minutes" + type: number + default: 45 + secrets: + deploy-role-arn: + description: "OIDC deploy role ARN (for match S3 access)" + required: true + match-password: + description: "Encryption passphrase for match certificates" + required: true + asc-key-id: + description: "App Store Connect API key ID" + required: true + asc-issuer-id: + description: "App Store Connect API issuer ID" + required: true + asc-key-content: + description: "Base64-encoded App Store Connect API key (.p8)" + required: true + +permissions: + id-token: write + contents: read + +jobs: + deploy-ios: + runs-on: macos-latest + timeout-minutes: ${{ inputs.timeout-minutes }} + defaults: + run: + working-directory: ${{ inputs.working-directory }} + steps: + - uses: actions/checkout@v4 + + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.deploy-role-arn }} + aws-region: ${{ inputs.region }} + + - uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node-version }} + cache: npm + cache-dependency-path: ${{ inputs.cache-dependency-path }} + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ inputs.ruby-version }} + bundler-cache: true + working-directory: ${{ inputs.working-directory }} + + - name: Install JS dependencies + run: npm ci + + - name: Install CocoaPods + run: bundle exec pod install --project-directory=ios + + - name: Build and upload + run: bundle exec fastlane ${{ inputs.fastlane-lane }} + env: + MATCH_PASSWORD: ${{ secrets.match-password }} + ASC_KEY_ID: ${{ secrets.asc-key-id }} + ASC_ISSUER_ID: ${{ secrets.asc-issuer-id }} + ASC_KEY_CONTENT: ${{ secrets.asc-key-content }} diff --git a/.github/workflows/ci-dotnet.yaml b/.github/workflows/ci-dotnet.yaml new file mode 100644 index 0000000..e12a927 --- /dev/null +++ b/.github/workflows/ci-dotnet.yaml @@ -0,0 +1,45 @@ +name: CI — .NET + +on: + workflow_call: + inputs: + dotnet-version: + description: ".NET SDK version" + type: string + default: "8.0.x" + working-directory: + description: "Directory containing the solution/project" + type: string + default: "." + solution: + description: "Solution or project file to build" + type: string + default: "*.sln" + run-tests: + description: "Run dotnet test" + type: boolean + default: true + +jobs: + ci: + runs-on: ubuntu-latest + timeout-minutes: 20 + defaults: + run: + working-directory: ${{ inputs.working-directory }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: ${{ inputs.dotnet-version }} + + - name: Restore + run: dotnet restore ${{ inputs.solution }} + + - name: Build + run: dotnet build ${{ inputs.solution }} --no-restore --configuration Release + + - name: Test + if: ${{ inputs.run-tests }} + run: dotnet test ${{ inputs.solution }} --no-build --configuration Release diff --git a/.github/workflows/ci-typescript-cdk.yaml b/.github/workflows/ci-typescript-cdk.yaml index 1d8a325..9d2d6e0 100644 --- a/.github/workflows/ci-typescript-cdk.yaml +++ b/.github/workflows/ci-typescript-cdk.yaml @@ -7,6 +7,22 @@ on: description: "Node.js version to use" type: string default: "24" + working-directory: + description: "Directory to run npm/tsc/cdk commands from" + type: string + default: "." + cache-dependency-path: + description: "Path to package-lock.json for npm cache" + type: string + default: "package-lock.json" + dotnet-version: + description: "Optional .NET SDK version (set up before CDK synth for repos with .NET assets)" + type: string + default: "" + dotnet-publish-project: + description: "Optional .NET project path to publish before CDK synth" + type: string + default: "" run-typecheck: description: "Run tsc --noEmit" type: boolean @@ -50,28 +66,43 @@ jobs: - uses: docker/setup-qemu-action@v3 if: ${{ inputs.enable-qemu }} + - uses: actions/setup-dotnet@v5 + if: ${{ inputs.dotnet-version != '' }} + with: + dotnet-version: ${{ inputs.dotnet-version }} + + - name: Publish .NET project + if: ${{ inputs.dotnet-publish-project != '' }} + run: dotnet publish ${{ inputs.dotnet-publish-project }} --configuration Release --runtime linux-arm64 --self-contained + - uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} cache: npm + cache-dependency-path: ${{ inputs.cache-dependency-path }} - name: Install dependencies + working-directory: ${{ inputs.working-directory }} run: npm ci - name: Type check if: ${{ inputs.run-typecheck }} + working-directory: ${{ inputs.working-directory }} run: npx tsc --noEmit - name: Lint if: ${{ inputs.run-lint }} + working-directory: ${{ inputs.working-directory }} run: npx eslint . - name: Run tests if: ${{ inputs.run-tests }} + working-directory: ${{ inputs.working-directory }} run: npx jest - name: CDK synth if: ${{ inputs.run-cdk-synth }} + working-directory: ${{ inputs.working-directory }} run: npx cdk synth --quiet - name: Conventions check