Question #122MediumTools & DevOps

Know how to create CI/CD pipeline - jenkins , github actions (created from the scratch and now successfully running)

#git

Answer

Overview

A CI/CD pipeline automates building, testing, and deploying your Flutter app every time code is pushed. GitHub Actions is the most common choice for Flutter projects; Jenkins is common in enterprise setups.


GitHub Actions — Flutter CI/CD from Scratch

Basic CI Pipeline (.github/workflows/ci.yml)

yaml
name: Flutter CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    name: Test & Analyze
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.x'
          channel: 'stable'

      - name: Install dependencies
        run: flutter pub get

      - name: Verify formatting
        run: dart format --output=none --set-exit-if-changed .

      - name: Analyze code
        run: flutter analyze --no-fatal-warnings

      - name: Run tests
        run: flutter test --coverage

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: coverage/lcov.info

Full CD Pipeline — Build & Deploy Android AAB

yaml
  build-android:
    name: Build Android Release
    runs-on: ubuntu-latest
    needs: test  # Only runs if test job passes

    steps:
      - uses: actions/checkout@v4

      - uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.x'

      - name: Install dependencies
        run: flutter pub get

      - name: Decode keystore
        run: |
          echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/app/keystore.jks

      - name: Build App Bundle
        env:
          KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
          KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
        run: |
          flutter build appbundle --release \
            --dart-define=API_URL=${{ secrets.API_URL }}

      - name: Upload AAB artifact
        uses: actions/upload-artifact@v3
        with:
          name: release-aab
          path: build/app/outputs/bundle/release/app-release.aab

Secrets Management in GitHub Actions

text
GitHub Repo → Settings → Secrets and variables → Actions → New repository secret

Add:
- KEYSTORE_BASE64 (base64 encoded keystore)
- KEY_STORE_PASSWORD
- KEY_ALIAS
- KEY_PASSWORD
- API_URL

Jenkins CI/CD (Enterprise)

groovy
// Jenkinsfile
pipeline {
    agent any

    environment {
        FLUTTER_HOME = '/usr/local/flutter'
        PATH = "${FLUTTER_HOME}/bin:${env.PATH}"
    }

    stages {
        stage('Checkout') {
            steps { checkout scm }
        }

        stage('Dependencies') {
            steps { sh 'flutter pub get' }
        }

        stage('Test') {
            steps {
                sh 'flutter analyze'
                sh 'flutter test'
            }
        }

        stage('Build') {
            steps {
                sh 'flutter build apk --release'
            }
        }

        stage('Archive') {
            steps {
                archiveArtifacts artifacts: 'build/app/outputs/apk/release/*.apk'
            }
        }
    }

    post {
        success { slackSend message: "✅ Build succeeded: ${env.JOB_NAME}" }
        failure { slackSend message: "❌ Build failed: ${env.JOB_NAME}" }
    }
}

GitHub Actions vs Jenkins

FeatureGitHub ActionsJenkins
SetupMinimal (YAML files)Heavy (server required)
HostingGitHub-hosted runnersSelf-hosted
CostFree for public/limited privateFree (but infra cost)
Flutter support
text
subosito/flutter-action
plugin
Manual setup
Best forOpen source / small teamsEnterprise / complex pipelines

Best Practice: Store all secrets in GitHub Secrets — never commit keys or passwords to the repo. Use environment-specific pipelines (staging vs production).