├── .env.example ├── .github ├── CODEOWNERS ├── SECURITY.md ├── renovate.json └── workflows │ ├── build.yml │ ├── changelog.yml │ ├── ci.yml │ ├── release.yml │ ├── scorecard.yml │ ├── tag.yml │ ├── update_version.yml │ └── windows.yml ├── .gitignore ├── .prettierrc.yml ├── LICENSE.md ├── android.Dockerfile ├── changelog.md ├── config ├── android.cue ├── flutter_version.cue ├── flutter_version.json ├── version.cue └── version.json ├── docker-compose.yml ├── docs ├── contributing.md └── src │ ├── .gitignore │ ├── badges.mdx │ ├── compile.js │ ├── content.mdx │ ├── contributing.mdx │ ├── license.mdx │ ├── package-lock.json │ ├── package.json │ └── readme.mdx ├── readme.md ├── script ├── build_windows.sh ├── container_structure_test.sh ├── copyFlutterVersion.js ├── createGitTag.js ├── docker_build_android.sh ├── docker_linux_entrypoint.sh ├── docker_windows_entrypoint.ps1 ├── latest_android_ndk.sh ├── latest_android_sdk_build_tools.sh ├── latest_android_sdk_command_line_tools.sh ├── latest_android_sdk_platforms.sh ├── renovate_validate.sh ├── setEnvironmentVariables.js ├── test.sh ├── test_windows.sh ├── updateAndroidVersions.gradle.kts ├── updateFastlaneVersion.js ├── updateFlutterVersion.js ├── update_changelog.sh └── update_test.sh ├── test └── android.yml ├── windows.Dockerfile └── windows.md /.env.example: -------------------------------------------------------------------------------- 1 | FLUTTER_VERSION=3.7.7 2 | FASTLANE_VERSION=2.213.0 3 | ANDROID_BUILD_TOOLS_VERSION=30.0.3 4 | ANDROID_PLATFORM_VERSIONS=28 31 33 5 | ENABLE_ANALYTICS=true 6 | ANDROID_NDK_VERSION=26.3.11579264 7 | CMAKE_VERSION=3.22.1 8 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @gmeligio 2 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Currently, this project is maintained by a single contributor and is in active development. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | If you discover a vulnerability in this project, please use GitHub’s private vulnerability reporting feature. 10 | 11 | 12 | 13 | Please avoid exposing sensitive details publicly. 14 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | "group:allNonMajor", 6 | "group:recommended", 7 | "group:monorepos", 8 | "schedule:weekly" 9 | ], 10 | "packageRules": [ 11 | { 12 | "description": "Schedule Github Actions updates on the first day of the month", 13 | "groupName": "github-actions", 14 | "matchDatasources": [ 15 | "github-tags" 16 | ], 17 | "schedule": [ 18 | "* 0-3 1 * *" 19 | ] 20 | } 21 | ], 22 | "customManagers": [ 23 | { 24 | "customType": "regex", 25 | "fileMatch": [ 26 | "^Dockerfile$" 27 | ], 28 | "matchStrings": [ 29 | "#\\s*renovate:\\s*release=(?.*?) depName=(?.*?)\\sARG .*?_VERSION=\"(?.*)\"\\s" 30 | ], 31 | "registryUrlTemplate": "https://deb.debian.org/debian?{{#if release }}release={{release}}{{else}}suite=stable{{/if}}&components=main,contrib,non-free&binaryArch=amd64", 32 | "datasourceTemplate": "deb" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | workflow_dispatch: 4 | 5 | # Read-only permissions by default 6 | permissions: 7 | contents: read 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | test_image: 15 | permissions: 16 | # Allow to write packages for the docker/scout-action to write a comment 17 | packages: write 18 | # Allow to write pull requests for the docker/scout-action to write a comment 19 | pull-requests: write 20 | # Allow to write security events for github/codeql-action/upload-sarif to upload SARIF results 21 | security-events: write 22 | runs-on: ubuntu-24.04 23 | env: 24 | IMAGE_REPOSITORY_NAME: flutter-android 25 | VERSION_MANIFEST: config/version.json 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | 30 | - name: Read environment variables from the version manifest 31 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 32 | env: 33 | GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} 34 | IMAGE_REPOSITORY_NAME: ${{ env.IMAGE_REPOSITORY_NAME }} 35 | VERSION_MANIFEST: ${{ env.VERSION_MANIFEST }} 36 | with: 37 | script: | 38 | const script = require('./script/setEnvironmentVariables.js') 39 | return await script({ core }) 40 | 41 | - name: Load image metadata 42 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 43 | id: metadata 44 | with: 45 | images: | 46 | ${{ env.IMAGE_REPOSITORY_PATH }} 47 | tags: | 48 | type=raw,value=${{ env.FLUTTER_VERSION }} 49 | 50 | - name: Set up Docker Buildx 51 | uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 52 | 53 | - name: Login to Docker Hub 54 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 55 | with: 56 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 57 | password: ${{ secrets.DOCKER_HUB_TOKEN }} 58 | 59 | - name: Build image and push to local Docker daemon 60 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 61 | with: 62 | file: android.Dockerfile 63 | load: true 64 | cache-from: type=gha 65 | cache-to: type=gha,mode=max 66 | labels: ${{ steps.metadata.outputs.labels }} 67 | tags: ${{ steps.metadata.outputs.tags }} 68 | target: android 69 | build-args: | 70 | flutter_version=${{ env.FLUTTER_VERSION }} 71 | fastlane_version=${{ env.FASTLANE_VERSION }} 72 | android_build_tools_version=${{ env.ANDROID_BUILD_TOOLS_VERSION }} 73 | android_platform_versions=${{ env.ANDROID_PLATFORM_VERSIONS }} 74 | android_ndk_version=${{ env.ANDROID_NDK_VERSION }} 75 | cmake_version=${{ env.CMAKE_VERSION }} 76 | 77 | - name: Test image 78 | uses: plexsystems/container-structure-test-action@c0a028aa96e8e82ae35be556040340cbb3e280ca # v0.3.0 79 | with: 80 | image: ${{ fromJSON(steps.metadata.outputs.json).tags[0] }} 81 | config: test/android.yml 82 | 83 | # TODO: Parallelize testing and vulnerability scanning 84 | - name: Scan with Docker Scout 85 | id: docker-scout 86 | uses: docker/scout-action@aceeb83b88f2ae54376891227858dda7af647183 # v1.18.1 87 | with: 88 | command: compare, recommendations 89 | # Use the Docker Hub image that is the first tag in the metadata 90 | image: local://${{ fromJson(steps.metadata.outputs.json).tags[0] }} 91 | # github-token is needed to be able to write the PR comment 92 | github-token: ${{ github.token }} 93 | only-fixed: true 94 | organization: ${{ secrets.DOCKER_HUB_USERNAME }} 95 | # sarif-file: output.sarif.json 96 | to-env: prod 97 | # Enable debug logging when needed 98 | # debug: true 99 | # verbose-debug: true 100 | 101 | validate_version_files: 102 | runs-on: ubuntu-24.04 103 | steps: 104 | - name: Checkout repository 105 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 106 | 107 | - name: Setup CUE 108 | uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 109 | with: 110 | repo: cue-lang/cue 111 | tag: v0.13.0 112 | digest: 59ba96137da07cd2cdd2e17ec33af81f850126f022f25dd96516f0b42071b6a9 113 | 114 | - name: Validate version.json and flutter_version.json with CUE 115 | run: | 116 | cue vet config/version.cue -d '#FlutterVersion' config/flutter_version.json 117 | cue vet config/version.cue -d '#Version' config/version.json 118 | 119 | validate_generated_config: 120 | runs-on: ubuntu-24.04 121 | steps: 122 | - name: Checkout repository 123 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 124 | 125 | - name: Setup CUE 126 | uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 127 | with: 128 | repo: cue-lang/cue 129 | tag: v0.13.0 130 | digest: 59ba96137da07cd2cdd2e17ec33af81f850126f022f25dd96516f0b42071b6a9 131 | 132 | - name: Generate test files with CUE 133 | run: | 134 | ./script/update_test.sh 135 | 136 | - name: Check if there are any changes in the git working tree 137 | run: | 138 | git add -A 139 | git diff --exit-code HEAD 140 | 141 | build_docs: 142 | runs-on: ubuntu-24.04 143 | steps: 144 | - name: Checkout repository 145 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 146 | 147 | - name: Setup NodeJS 148 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 149 | with: 150 | cache: npm 151 | cache-dependency-path: docs/src/package-lock.json 152 | node-version-file: docs/src/package.json 153 | 154 | - name: Update documentation 155 | working-directory: docs/src 156 | run: | 157 | npm ci --prefer-offline 158 | npm run build 159 | 160 | - name: Check if there are any changes in the git working tree 161 | run: | 162 | git add -A 163 | git diff --exit-code HEAD 164 | 165 | test_gradle: 166 | permissions: 167 | # Allow to read packages to pull the container image from GitHub Container Registry 168 | packages: read 169 | runs-on: ubuntu-24.04 170 | container: 171 | image: ghcr.io/${{ github.repository_owner }}/flutter-android:${{ vars.FLUTTER_VERSION }} 172 | credentials: 173 | username: ${{ github.actor }} 174 | password: ${{ github.token }} 175 | steps: 176 | - name: Checkout repository 177 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 178 | 179 | - name: Read version.json 180 | id: version-json 181 | run: | 182 | { 183 | echo "content<> $GITHUB_OUTPUT 187 | 188 | - name: Set environment variables from version.json 189 | run: | 190 | echo "FLUTTER_VERSION=${{ fromJson( steps.version-json.outputs.content ).flutter.version }}" >> $GITHUB_ENV 191 | echo "FLUTTER_CHANNEL=${{ fromJson( steps.version-json.outputs.content ).flutter.channel }}" >> $GITHUB_ENV 192 | 193 | - name: Setup Flutter 194 | run: | 195 | cd $FLUTTER_ROOT 196 | git fetch origin ${{ env.FLUTTER_VERSION }}:${{ env.FLUTTER_VERSION }} 197 | git switch --discard-changes ${{ env.FLUTTER_VERSION }} 198 | 199 | - name: Create test application 200 | run: | 201 | flutter create test_app 202 | 203 | - name: Update default Android platform versions in Flutter 204 | working-directory: test_app/android 205 | run: | 206 | cat ../../script/updateAndroidVersions.gradle.kts >> app/build.gradle.kts 207 | ./gradlew --warning-mode all updateAndroidVersions 208 | 209 | - name: Setup CUE 210 | uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 211 | with: 212 | repo: cue-lang/cue 213 | tag: v0.13.0 214 | digest: 59ba96137da07cd2cdd2e17ec33af81f850126f022f25dd96516f0b42071b6a9 215 | 216 | - name: Validate version.json with CUE 217 | run: cue vet config/version.cue -d '#Version' config/version.json 218 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | paths: 6 | - config/version.json 7 | workflow_dispatch: 8 | 9 | jobs: 10 | changelog: 11 | runs-on: ubuntu-24.04 12 | env: 13 | IMAGE_REPOSITORY_NAME: flutter-android 14 | VERSION_MANIFEST: config/version.json 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 18 | with: 19 | # TODO: Fetch only a few commits after using --unreleased in git-cliff 20 | # Fetch all commits to use as input for the changelog generation 21 | fetch-depth: 0 22 | # Fetch all tags to use as input for the changelog generation 23 | fetch-tags: true 24 | 25 | - name: Setup git-cliff 26 | uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 27 | with: 28 | repo: orhun/git-cliff 29 | tag: v2.8.0 30 | digest: 17da092783079c63a0fb14c24fbfa0d3b589e225c6ef01c93111e39cecbc88e8 31 | 32 | - name: Read environment variables from the version manifest 33 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 34 | env: 35 | GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} 36 | IMAGE_REPOSITORY_NAME: ${{ env.IMAGE_REPOSITORY_NAME }} 37 | VERSION_MANIFEST: ${{ env.VERSION_MANIFEST }} 38 | with: 39 | script: | 40 | const script = require('./script/setEnvironmentVariables.js') 41 | return await script({ core }) 42 | 43 | - name: Update changelog 44 | run: | 45 | git-cliff -v --tag ${{ env.FLUTTER_VERSION }} --github-repo ${{ github.repository }} --output changelog.md 46 | 47 | - name: Generate authentication token with GitHub App to trigger Actions 48 | uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 49 | id: app-token 50 | with: 51 | app-id: ${{ secrets.VERIFIED_COMMIT_ID }} 52 | private-key: ${{ secrets.VERIFIED_COMMIT_KEY }} 53 | repositories: ${{ github.event.repository.name }} 54 | owner: ${{ github.repository_owner }} 55 | 56 | - name: Commit and push changelog 57 | uses: grafana/github-api-commit-action@b1d81091e8480dd11fcea8bc1f0ab977a0376ca5 # v1.0.0 58 | with: 59 | commit-message: "chore(release): prepare for ${{ env.FLUTTER_VERSION }}" 60 | stage-all-files: true 61 | token: ${{ steps.app-token.outputs.token }} 62 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | paths-ignore: 6 | - changelog.md 7 | workflow_dispatch: 8 | 9 | # Read-only permissions by default 10 | permissions: 11 | contents: read 12 | 13 | env: 14 | IMAGE_REPOSITORY_NAME: flutter-android 15 | VERSION_MANIFEST: config/version.json 16 | 17 | jobs: 18 | test_image: 19 | runs-on: ubuntu-24.04 20 | env: 21 | ANDROID_BUILD_TOOLS_VERSION: 30.0.3 22 | steps: 23 | - name: Checkout repository 24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | 26 | - name: Login to Docker Hub 27 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 28 | with: 29 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 30 | password: ${{ secrets.DOCKER_HUB_TOKEN }} 31 | 32 | - name: Setup CUE 33 | uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 34 | with: 35 | repo: cue-lang/cue 36 | tag: v0.13.0 37 | digest: 59ba96137da07cd2cdd2e17ec33af81f850126f022f25dd96516f0b42071b6a9 38 | 39 | - name: Read environment variables from the version manifest 40 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 41 | env: 42 | GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} 43 | IMAGE_REPOSITORY_NAME: ${{ env.IMAGE_REPOSITORY_NAME }} 44 | VERSION_MANIFEST: ${{ env.VERSION_MANIFEST }} 45 | with: 46 | script: | 47 | const script = require('./script/setEnvironmentVariables.js') 48 | return await script({ core }) 49 | 50 | - name: Load image metadata 51 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 52 | id: metadata 53 | with: 54 | images: | 55 | ${{ env.IMAGE_REPOSITORY_PATH }} 56 | tags: | 57 | type=raw,value=${{ env.FLUTTER_VERSION }} 58 | 59 | - name: Set up Docker Buildx 60 | uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 61 | 62 | - name: Build image and push to local Docker daemon 63 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 64 | with: 65 | file: android.Dockerfile 66 | load: true 67 | cache-from: type=gha 68 | cache-to: type=gha,mode=max 69 | tags: ${{ steps.metadata.outputs.tags }} 70 | labels: ${{ steps.metadata.outputs.labels }} 71 | target: android 72 | build-args: | 73 | flutter_version=${{ env.FLUTTER_VERSION }} 74 | fastlane_version=${{ env.FASTLANE_VERSION }} 75 | android_build_tools_version=${{ env.ANDROID_BUILD_TOOLS_VERSION }} 76 | android_platform_versions=${{ env.ANDROID_PLATFORM_VERSIONS }} 77 | android_ndk_version=${{ env.ANDROID_NDK_VERSION }} 78 | cmake_version=${{ env.CMAKE_VERSION }} 79 | 80 | - name: Test image 81 | uses: plexsystems/container-structure-test-action@c0a028aa96e8e82ae35be556040340cbb3e280ca # v0.3.0 82 | with: 83 | image: ${{ fromJSON(steps.metadata.outputs.json).tags[0] }} 84 | config: test/android.yml 85 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - '*' 5 | workflow_dispatch: 6 | 7 | # Read-only permissions by default 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | release_android: 13 | permissions: 14 | # Allow to write packages to push the container image to the Github Container Registry 15 | packages: write 16 | # Allow to write security events to upload the results to code-scanning dashboard. 17 | security-events: write 18 | runs-on: ubuntu-24.04 19 | env: 20 | IMAGE_REPOSITORY_NAME: flutter-android 21 | ANDROID_BUILD_TOOLS_VERSION: 30.0.3 22 | VERSION_MANIFEST: config/version.json 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 26 | 27 | - name: Read environment variables from the version manifest 28 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 29 | env: 30 | GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} 31 | IMAGE_REPOSITORY_NAME: ${{ env.IMAGE_REPOSITORY_NAME }} 32 | VERSION_MANIFEST: ${{ env.VERSION_MANIFEST }} 33 | with: 34 | script: | 35 | const script = require('./script/setEnvironmentVariables.js') 36 | return await script({ core }) 37 | 38 | - name: Load image metadata 39 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 40 | id: metadata 41 | with: 42 | images: | 43 | ${{ env.IMAGE_REPOSITORY_PATH }} 44 | ghcr.io/${{ env.IMAGE_REPOSITORY_PATH }} 45 | quay.io/${{ env.IMAGE_REPOSITORY_PATH }} 46 | tags: | 47 | type=raw,value=${{ env.FLUTTER_VERSION }} 48 | 49 | - name: Set up Docker Buildx 50 | uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 51 | 52 | - name: Login to Docker Hub 53 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 54 | with: 55 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 56 | password: ${{ secrets.DOCKER_HUB_TOKEN }} 57 | 58 | - name: Login to GitHub Container Registry 59 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 60 | with: 61 | registry: ghcr.io 62 | username: ${{ github.actor }} 63 | password: ${{ github.token }} 64 | 65 | - name: Login to Quay.io 66 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 67 | with: 68 | registry: quay.io 69 | username: ${{ secrets.QUAY_USERNAME }} 70 | password: ${{ secrets.QUAY_ROBOT_TOKEN }} 71 | 72 | - name: Build image and push it to registries 73 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 74 | with: 75 | file: android.Dockerfile 76 | push: true 77 | cache-from: type=gha 78 | cache-to: type=gha,mode=max 79 | labels: ${{ steps.metadata.outputs.labels }} 80 | tags: ${{ steps.metadata.outputs.tags }} 81 | target: android 82 | build-args: | 83 | flutter_version=${{ env.FLUTTER_VERSION }} 84 | fastlane_version=${{ env.FASTLANE_VERSION }} 85 | android_build_tools_version=${{ env.ANDROID_BUILD_TOOLS_VERSION }} 86 | android_platform_versions=${{ env.ANDROID_PLATFORM_VERSIONS }} 87 | android_ndk_version=${{ env.ANDROID_NDK_VERSION }} 88 | cmake_version=${{ env.CMAKE_VERSION }} 89 | 90 | - name: Update Docker Hub description 91 | uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4.0.2 92 | with: 93 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 94 | password: ${{ secrets.DOCKER_HUB_TOKEN }} 95 | repository: ${{ env.IMAGE_REPOSITORY_PATH }} 96 | short-description: ${{ github.event.repository.description }} 97 | readme-filepath: readme.md 98 | 99 | - name: Record image in Docker Scout environment 100 | id: docker-scout-environment 101 | uses: docker/scout-action@aceeb83b88f2ae54376891227858dda7af647183 # v1.18.1 102 | with: 103 | command: environment, cves 104 | # Use the Docker Hub image that is the first tag in the metadata 105 | image: registry://${{ fromJson(steps.metadata.outputs.json).tags[0] }} 106 | environment: prod 107 | only-fixed: true 108 | organization: ${{ secrets.DOCKER_HUB_USERNAME }} 109 | sarif-file: sarif.json 110 | 111 | - name: Generate authentication token with GitHub App to trigger Actions 112 | uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 113 | id: app-token 114 | with: 115 | app-id: ${{ secrets.VERIFIED_COMMIT_ID }} 116 | private-key: ${{ secrets.VERIFIED_COMMIT_KEY }} 117 | repositories: ${{ github.event.repository.name }} 118 | owner: ${{ github.repository_owner }} 119 | 120 | - name: Update bootstrap image tag in environment variable 121 | run: gh variable set FLUTTER_VERSION --body "${{ env.FLUTTER_VERSION }}" 122 | env: 123 | GH_TOKEN: ${{ steps.app-token.outputs.token }} 124 | 125 | # Upload the results to GitHub's code scanning dashboard (optional). 126 | # Commenting out will disable upload of results to your repo's Code Scanning dashboard 127 | - name: Upload to code-scanning 128 | uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 129 | with: 130 | sarif_file: sarif.json 131 | 132 | # TODO: Use kaniko for building and pushing after slowness is solved 133 | # TODO: https://github.com/GoogleContainerTools/kaniko/issues/970 134 | # TODO: https://github.com/GoogleContainerTools/kaniko/issues/875 135 | # TODO: Use kaniko for building and pushing after pushing to Docker daemon is solved, to be able to test Docker image, with the following issues 136 | # TODO: https://github.com/GoogleContainerTools/kaniko/issues/1331 137 | # - name: Build image and push it to registries 138 | # uses: int128/kaniko-action@v1 139 | # with: 140 | # push: true 141 | # cache: true 142 | # cache-repository: ${{ steps.ecr-cache.outputs.repository-uri }} 143 | # tags: ${{ steps.metadata.outputs.tags }} 144 | # labels: ${{ steps.metadata.outputs.labels }} 145 | # build-args: | 146 | # flutter_version=${{ env.FLUTTER_VERSION }} 147 | # android_build_tools_version=${{ env.ANDROID_BUILD_TOOLS_VERSION }} 148 | # android_platform_versions=${{ env.ANDROID_PLATFORM_VERSIONS }} 149 | # kaniko-args: | 150 | # --skip-unused-stages=true 151 | # --use-new-run=true 152 | # --snapshotMode=redo 153 | # target: android 154 | # executor: gcr.io/kaniko-project/executor:latest 155 | # TODO: https://github.com/snok/container-retention-policy 156 | # TODO: Push a build image before the final image 157 | # TODO: Run basic tests with build image 158 | # TODO: Push final image only if tests pass https://redhat-cop.github.io/ci/publishing-images.html 159 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: '15 11 * * 2' 14 | push: 15 | branches: 16 | - main 17 | 18 | # Declare default permissions as read only. 19 | permissions: 20 | contents: read 21 | 22 | jobs: 23 | analysis: 24 | name: Scorecard analysis 25 | runs-on: ubuntu-24.04 26 | permissions: 27 | # Allow to write id-token to publish results and get a badge (see publish_results below). 28 | id-token: write 29 | # Allow to write security events to upload the results to code-scanning dashboard. 30 | security-events: write 31 | # Uncomment the permissions below if installing in a private repository. 32 | # contents: read 33 | # actions: read 34 | 35 | steps: 36 | - name: Checkout code 37 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 38 | with: 39 | persist-credentials: false 40 | 41 | - name: Run analysis 42 | uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 43 | with: 44 | results_file: results.sarif 45 | results_format: sarif 46 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 47 | # - you want to enable the Branch-Protection check on a *public* repository, or 48 | # - you are installing Scorecard on a *private* repository 49 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional. 50 | repo_token: ${{ github.token }} 51 | 52 | # Public repositories: 53 | # - Publish results to OpenSSF REST API for easy access by consumers 54 | # - Allows the repository to include the Scorecard badge. 55 | # - See https://github.com/ossf/scorecard-action#publishing-results. 56 | # For private repositories: 57 | # - `publish_results` will always be set to `false`, regardless 58 | # of the value entered here. 59 | publish_results: true 60 | 61 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 62 | # format to the repository Actions tab. 63 | - name: Upload artifact 64 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 65 | with: 66 | name: SARIF file 67 | path: results.sarif 68 | retention-days: 5 69 | 70 | # Upload the results to GitHub's code scanning dashboard (optional). 71 | # Commenting out will disable upload of results to your repo's Code Scanning dashboard 72 | - name: Upload to code-scanning 73 | uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 74 | with: 75 | sarif_file: results.sarif 76 | -------------------------------------------------------------------------------- /.github/workflows/tag.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | paths: 6 | - changelog.md 7 | workflow_dispatch: 8 | 9 | jobs: 10 | create_git_tag: 11 | runs-on: ubuntu-24.04 12 | env: 13 | IMAGE_REPOSITORY_NAME: flutter-android 14 | VERSION_MANIFEST: config/version.json 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 18 | 19 | - name: Generate authentication token with GitHub App to trigger Actions 20 | uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 21 | id: app-token 22 | with: 23 | app-id: ${{ secrets.VERIFIED_COMMIT_ID }} 24 | private-key: ${{ secrets.VERIFIED_COMMIT_KEY }} 25 | repositories: ${{ github.event.repository.name }} 26 | owner: ${{ github.repository_owner }} 27 | 28 | - name: Read environment variables from the version manifest 29 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 30 | env: 31 | GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} 32 | IMAGE_REPOSITORY_NAME: ${{ env.IMAGE_REPOSITORY_NAME }} 33 | VERSION_MANIFEST: ${{ env.VERSION_MANIFEST }} 34 | with: 35 | script: | 36 | const script = require('./script/setEnvironmentVariables.js') 37 | return await script({ core }) 38 | 39 | - name: Create Tag for a New Flutter Version 40 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 41 | env: 42 | OLD_FLUTTER_VERSION: ${{ vars.FLUTTER_VERSION }} 43 | NEW_FLUTTER_VERSION: ${{ env.FLUTTER_VERSION }} 44 | with: 45 | github-token: ${{ steps.app-token.outputs.token }} 46 | script: | 47 | const script = require('./script/createGitTag.js') 48 | await script({ core, context, github }) 49 | -------------------------------------------------------------------------------- /.github/workflows/update_version.yml: -------------------------------------------------------------------------------- 1 | on: 2 | schedule: 3 | - cron: '0 0 * * MON-FRI' 4 | workflow_dispatch: 5 | 6 | # Declare default permissions as read only. 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | update_flutter_version: 12 | permissions: 13 | # Allow to write contents to push commits 14 | contents: write 15 | # Allow to write pull requests to push commits and write comments 16 | pull-requests: write 17 | runs-on: ubuntu-24.04 18 | outputs: 19 | new_version: ${{ steps.update_flutter_version.outputs.result }} 20 | flutter_version_artifact_id: ${{ steps.upload-version.outputs.artifact-id }} 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 24 | 25 | - name: Update latest Flutter version 26 | id: update_flutter_version 27 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 28 | with: 29 | script: | 30 | const script = require('./script/updateFlutterVersion.js') 31 | return await script({core, fetch}) 32 | 33 | - name: Setup CUE 34 | if: ${{ steps.update_flutter_version.outputs.result == 'true' }} 35 | uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 36 | with: 37 | repo: cue-lang/cue 38 | tag: v0.13.0 39 | digest: 59ba96137da07cd2cdd2e17ec33af81f850126f022f25dd96516f0b42071b6a9 40 | 41 | - name: Validate version.json with CUE 42 | if: ${{ steps.update_flutter_version.outputs.result == 'true' }} 43 | run: cue vet config/version.cue -d '#FlutterVersion' config/flutter_version.json 44 | 45 | - name: Upload artifact with the new Flutter version 46 | if: ${{ steps.update_flutter_version.outputs.result == 'true' }} 47 | id: upload-version 48 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 49 | with: 50 | name: flutter_version.json 51 | path: config/flutter_version.json 52 | 53 | update_android_version: 54 | permissions: 55 | # Allow to write contents to push commits 56 | contents: write 57 | # Allow to read packages to pull the container image from GitHub Container Registry 58 | packages: read 59 | # Allow to write pull requests to create a pull request 60 | pull-requests: write 61 | needs: update_flutter_version 62 | if: ${{ needs.update_flutter_version.outputs.new_version == 'true' }} 63 | outputs: 64 | version_artifact_id: ${{ steps.upload-version.outputs.artifact-id }} 65 | runs-on: ubuntu-24.04 66 | container: 67 | image: ghcr.io/${{ github.repository_owner }}/flutter-android:${{ vars.FLUTTER_VERSION }} 68 | credentials: 69 | username: ${{ github.actor }} 70 | password: ${{ github.token }} 71 | steps: 72 | - name: Checkout repository 73 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 74 | 75 | # TODO: Workaround because actions/download-artifact can't overwrite existing files 76 | # Check if this workaround can be removed after the following issues are fixed: 77 | # https://github.com/actions/download-artifact/issues/225 78 | # https://github.com/actions/download-artifact/issues/138 79 | - name: Delete flutter_version.json 80 | run: rm config/flutter_version.json 81 | 82 | - name: Download artifact with the new Flutter version 83 | uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 84 | with: 85 | artifact-ids: ${{ needs.update_flutter_version.outputs.flutter_version_artifact_id }} 86 | path: config 87 | # Download to the configured path instead of separated directories by artifact id 88 | merge-multiple: true 89 | 90 | - name: Copy Flutter version into version manifest and export FLUTTER_* environment variables 91 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 92 | with: 93 | script: | 94 | const script = require('./script/copyFlutterVersion.js') 95 | await script({core}) 96 | 97 | - name: Update latest Fastlane version 98 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 99 | with: 100 | script: | 101 | const script = require('./script/updateFastlaneVersion.js') 102 | await script({core, fetch}) 103 | 104 | - name: Setup Flutter 105 | run: | 106 | cd $FLUTTER_ROOT 107 | git fetch origin ${{ env.FLUTTER_VERSION }}:${{ env.FLUTTER_VERSION }} 108 | git switch --discard-changes ${{ env.FLUTTER_VERSION }} 109 | 110 | # TODO: Create test app in specific folder with step id, to allow parallel execution 111 | - name: Create test application 112 | run: | 113 | flutter create test_app 114 | 115 | # TODO: Cache gradle https://github.com/gradle/gradle-build-action 116 | - name: Update default Android platform versions in Flutter 117 | working-directory: test_app/android 118 | run: | 119 | cat ../../script/updateAndroidVersions.gradle.kts >> app/build.gradle.kts 120 | ./gradlew --warning-mode all updateAndroidVersions 121 | 122 | - name: Clean test application 123 | run: | 124 | rm -rf test_app 125 | 126 | - name: Upload artifact with the updated version.json 127 | id: upload-version 128 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 129 | with: 130 | name: version.json 131 | path: config/version.json 132 | 133 | validate_config_version: 134 | needs: update_android_version 135 | runs-on: ubuntu-24.04 136 | steps: 137 | - name: Checkout repository 138 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 139 | 140 | # TODO: Workaround because actions/download-artifact can't overwrite existing files 141 | # Check if this workaround can be removed after the following issues are fixed: 142 | # https://github.com/actions/download-artifact/issues/225 143 | # https://github.com/actions/download-artifact/issues/138 144 | - name: Delete version.json 145 | run: rm config/version.json 146 | 147 | - name: Download artifact with the new Flutter version 148 | uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 149 | with: 150 | artifact-ids: ${{ needs.update_android_version.outputs.version_artifact_id }} 151 | path: config 152 | # Download to the configured path instead of separated directories by artifact id 153 | merge-multiple: true 154 | 155 | - name: Setup CUE 156 | uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 157 | with: 158 | repo: cue-lang/cue 159 | tag: v0.13.0 160 | digest: 59ba96137da07cd2cdd2e17ec33af81f850126f022f25dd96516f0b42071b6a9 161 | 162 | - name: Validate version.json with CUE 163 | run: cue vet config/version.cue -d '#Version' config/version.json 164 | 165 | update_docs_and_create_pr: 166 | needs: 167 | - update_android_version 168 | - validate_config_version 169 | runs-on: ubuntu-24.04 170 | env: 171 | IMAGE_REPOSITORY_NAME: flutter-android 172 | VERSION_MANIFEST: config/version.json 173 | steps: 174 | - name: Checkout repository 175 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 176 | 177 | # TODO: Workaround because actions/download-artifact can't overwrite existing files 178 | # Check if this workaround can be removed after the following issues are fixed: 179 | # https://github.com/actions/download-artifact/issues/225 180 | # https://github.com/actions/download-artifact/issues/138 181 | - name: Delete version.json 182 | run: rm config/version.json 183 | 184 | - name: Download artifact with the new Flutter version 185 | uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 186 | with: 187 | artifact-ids: ${{ needs.update_android_version.outputs.version_artifact_id }} 188 | path: config 189 | # Download to the configured path instead of separated directories by artifact id 190 | merge-multiple: true 191 | 192 | - name: Setup NodeJS 193 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 194 | with: 195 | cache: npm 196 | cache-dependency-path: docs/src/package-lock.json 197 | node-version-file: docs/src/package.json 198 | 199 | - name: Update documentation 200 | working-directory: docs/src 201 | run: | 202 | npm ci --prefer-offline 203 | npm run build 204 | 205 | - name: Read environment variables from the version manifest 206 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 207 | env: 208 | GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} 209 | IMAGE_REPOSITORY_NAME: ${{ env.IMAGE_REPOSITORY_NAME }} 210 | VERSION_MANIFEST: ${{ env.VERSION_MANIFEST }} 211 | with: 212 | script: | 213 | const script = require('./script/setEnvironmentVariables.js') 214 | return await script({ core }) 215 | 216 | - name: Create commit message variable 217 | run: | 218 | echo "COMMIT_MESSAGE=chore(release): update flutter dependencies in version.json for ${{ env.FLUTTER_VERSION }}" >> $GITHUB_ENV 219 | 220 | - name: Generate authentication token with GitHub App to trigger Actions 221 | uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 222 | id: app-token 223 | with: 224 | app-id: ${{ secrets.VERIFIED_COMMIT_ID }} 225 | private-key: ${{ secrets.VERIFIED_COMMIT_KEY }} 226 | repositories: ${{ github.event.repository.name }} 227 | owner: ${{ github.repository_owner }} 228 | 229 | # TODO: Generate changelog for the new flutter version, that will be the new tag 230 | - name: Create pull request if there are changes 231 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 232 | with: 233 | commit-message: ${{ env.COMMIT_MESSAGE }} 234 | branch: update-flutter-dependencies/${{ env.FLUTTER_VERSION }} 235 | sign-commits: true 236 | title: ${{ env.COMMIT_MESSAGE }} 237 | token: ${{ steps.app-token.outputs.token }} 238 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | workflow_dispatch: 4 | 5 | # Read-only permissions by default 6 | permissions: 7 | contents: read 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | test_windows: 15 | permissions: 16 | # Allow to write packages for the docker/scout-action to write a comment 17 | packages: write 18 | # Allow to write pull requests for the docker/scout-action to write a comment 19 | pull-requests: write 20 | # Allow to write security events for github/codeql-action/upload-sarif to upload SARIF results 21 | security-events: write 22 | runs-on: windows-2025 23 | env: 24 | IMAGE_REPOSITORY_NAME: flutter-android 25 | VERSION_MANIFEST: config/version.json 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | 30 | - name: Login to Docker Hub 31 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 32 | with: 33 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 34 | password: ${{ secrets.DOCKER_HUB_TOKEN }} 35 | 36 | - name: Read environment variables from the version manifest 37 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 38 | env: 39 | GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }} 40 | IMAGE_REPOSITORY_NAME: ${{ env.IMAGE_REPOSITORY_NAME }} 41 | VERSION_MANIFEST: ${{ env.VERSION_MANIFEST }} 42 | with: 43 | script: | 44 | const script = require('./script/setEnvironmentVariables.js') 45 | return await script({ core }) 46 | 47 | # - name: Load image metadata 48 | # uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 49 | # id: metadata 50 | # with: 51 | # images: | 52 | # ${{ env.IMAGE_REPOSITORY_PATH }} 53 | # tags: | 54 | # type=raw,value=${{ env.FLUTTER_VERSION }} 55 | 56 | # - name: Set up Docker Buildx 57 | # uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 58 | 59 | - name: Build image and push to local Docker daemon 60 | shell: powershell 61 | run: | 62 | docker build . -f windows.Dockerfile --build-arg flutter_version=${{ env.FLUTTER_VERSION }} -t ${{ env.IMAGE_REPOSITORY_PATH }} 63 | 64 | # - name: Build image and push to local Docker daemon 65 | # uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 66 | # with: 67 | # file: windows.Dockerfile 68 | # load: true 69 | # cache-from: type=gha 70 | # cache-to: type=gha,mode=max 71 | # labels: ${{ steps.metadata.outputs.labels }} 72 | # tags: ${{ steps.metadata.outputs.tags }} 73 | # target: android 74 | # build-args: | 75 | # flutter_version=${{ env.FLUTTER_VERSION }} 76 | 77 | # - name: Test image 78 | # uses: plexsystems/container-structure-test-action@c0a028aa96e8e82ae35be556040340cbb3e280ca # v0.3.0 79 | # with: 80 | # image: ${{ fromJSON(steps.metadata.outputs.json).tags[0] }} 81 | # config: test/android.yml 82 | 83 | # # TODO: Parallelize testing and vulnerability scanning 84 | # - name: Scan with Docker Scout 85 | # id: docker-scout 86 | # uses: docker/scout-action@0133ff88fe16d4a412dc4827a8fccbccb6b583e0 # v1.16.3 87 | # with: 88 | # command: compare, recommendations 89 | # # Use the Docker Hub image that is the first tag in the metadata 90 | # image: local://${{ fromJson(steps.metadata.outputs.json).tags[0] }} 91 | # # github-token is needed to be able to write the PR comment 92 | # github-token: ${{ github.token }} 93 | # only-fixed: true 94 | # organization: ${{ secrets.DOCKER_HUB_USERNAME }} 95 | # # sarif-file: output.sarif.json 96 | # to-env: prod 97 | # # Enable debug logging when needed 98 | # # debug: true 99 | # # verbose-debug: true 100 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.env 2 | /test_app 3 | /.vscode -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | trailingComma: 'es5' 2 | tabWidth: 2 3 | semi: false 4 | singleQuote: true 5 | overrides: 6 | - files: '*.json' 7 | options: 8 | tabWidth: 4 9 | - files: 'renovate.json' 10 | options: 11 | tabWidth: 2 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | MIT License 4 | 5 | Copyright (c) 2023-2025 Eligio Alejandro Mariño Garcés 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /android.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:12.11-slim@sha256:90522eeb7e5923ee2b871c639059537b30521272f10ca86fdbbbb2b75a8c40cd AS flutter 2 | 3 | SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] 4 | 5 | ENV LANG=C.UTF-8 6 | 7 | # renovate: release=bullseye depName=curl 8 | ARG CURL_VERSION="7.88.1-10+deb12u12" 9 | # renovate: release=bullseye depName=git 10 | ARG GIT_VERSION="1:2.39.5-0+deb12u2" 11 | # renovate: release=bullseye depName=lcov 12 | ARG LCOV_VERSION="1.16-1" 13 | # renovate: release=bullseye depName=ca-certificates 14 | ARG CA_CERTIFICATES_VERSION="20230311" 15 | # renovate: release=bullseye depName=unzip 16 | ARG UNZIP_VERSION="6.0-28" 17 | 18 | USER root 19 | RUN apt-get update \ 20 | && apt-get install -y --no-install-recommends \ 21 | # Flutter dependencies 22 | # bc=1.07.1-3build1 \ 23 | # build-essential=12.9ubuntu3 \ 24 | # For downloading Dart SDK 25 | curl="$CURL_VERSION" \ 26 | git="$GIT_VERSION" \ 27 | # For generating coverage reports 28 | lcov="$LCOV_VERSION" \ 29 | # libglu1-mesa=9.0.2-1 \ 30 | # libsqlite3-0=3.37.2-2ubuntu0.1 \ 31 | # libstdc++6=12.1.0-2ubuntu1~22.04 \ 32 | # libpulse0=1:15.99.1+dfsg1-1ubuntu2 \ 33 | # locales=2.35-0ubuntu3.1 \ 34 | # openssh-client=1:8.9p1-3ubuntu0.1 \ 35 | # software-properties-common=0.99.22.5 \ 36 | # zip=3.0-12build2 \ 37 | ca-certificates="$CA_CERTIFICATES_VERSION" \ 38 | unzip="$UNZIP_VERSION" \ 39 | && rm -rf /var/lib/apt/lists/* 40 | 41 | # After finishing with root user, set the HOME folder for the non-root user 42 | ENV HOME=/home/flutter 43 | 44 | # The Github runner clones the repository with uid 1001 and gid 1001. This uid 1001 needs to be the set to the container user to give ownership to the repository folder. 45 | # See https://github.com/actions/checkout/issues/766 46 | RUN groupadd --gid 1001 flutter \ 47 | && useradd --create-home \ 48 | --shell /bin/bash \ 49 | --uid 1001 \ 50 | --gid flutter \ 51 | flutter 52 | USER flutter:flutter 53 | WORKDIR "$HOME" 54 | 55 | ENV SDK_ROOT="$HOME/sdks" 56 | ENV FLUTTER_ROOT="$SDK_ROOT/flutter" 57 | ENV PATH="$PATH:$FLUTTER_ROOT/bin:$FLUTTER_ROOT/bin/cache/dart-sdk/bin" 58 | 59 | ARG flutter_version 60 | 61 | RUN git clone \ 62 | --depth 1 \ 63 | --branch "$flutter_version" \ 64 | https://github.com/flutter/flutter.git \ 65 | "$FLUTTER_ROOT" \ 66 | && chown -R flutter:flutter "$FLUTTER_ROOT" \ 67 | && flutter --version \ 68 | && flutter config --no-cli-animations \ 69 | && dart --disable-analytics \ 70 | && flutter config \ 71 | --no-cli-animations \ 72 | --no-analytics \ 73 | --no-enable-android \ 74 | --no-enable-web \ 75 | --no-enable-linux-desktop \ 76 | --no-enable-windows-desktop \ 77 | --no-enable-fuchsia \ 78 | --no-enable-custom-devices \ 79 | --no-enable-ios \ 80 | --no-enable-macos-desktop \ 81 | && flutter doctor 82 | 83 | COPY --chown=flutter:flutter ./script/docker_linux_entrypoint.sh "$HOME/docker_entrypoint.sh" 84 | RUN chmod +x "$HOME/docker_entrypoint.sh" 85 | 86 | ENTRYPOINT [ "/home/flutter/docker_entrypoint.sh" ] 87 | 88 | #----------------------------------------------- 89 | #----------------------------------------------- 90 | #----------------------------------------------- 91 | 92 | FROM flutter AS fastlane 93 | 94 | SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] 95 | 96 | # renovate: release=bullseye depName=ruby-dev 97 | ARG RUBY_VERSION="1:3.1" 98 | # renovate: release=bullseye depName=build-essential 99 | ENV BUILD_ESSENTIAL_VERSION="12.9" 100 | 101 | USER root 102 | RUN apt-get update \ 103 | && apt-get install -y --no-install-recommends \ 104 | # Fastlane dependencies 105 | ruby-full="$RUBY_VERSION" \ 106 | build-essential="$BUILD_ESSENTIAL_VERSION" \ 107 | && rm -rf /var/lib/apt/lists/* 108 | 109 | USER flutter:flutter 110 | 111 | ENV RUBY_ROOT="$SDK_ROOT/ruby" 112 | ENV GEM_HOME="$RUBY_ROOT" 113 | ENV GEM_PATH="$GEM_HOME" 114 | ENV PATH="$PATH:$GEM_HOME/bin" 115 | 116 | # Fastlane configuration 117 | ENV FASTLANE_OPT_OUT_USAGE="YES" 118 | ENV FASTLANE_SKIP_UPDATE_CHECK="YES" 119 | ENV FASTLANE_HIDE_CHANGELOG="YES" 120 | 121 | # renovate: datasource=rubygems depName=fastlane versioning=ruby 122 | ENV BUNDLER_VERSION="2.4.14" 123 | 124 | RUN gem install --no-document --version "$BUNDLER_VERSION" bundler 125 | 126 | ENV FASTLANE_ROOT="$SDK_ROOT/fastlane" 127 | 128 | RUN mkdir -p "$FASTLANE_ROOT" 129 | 130 | WORKDIR "$FASTLANE_ROOT" 131 | 132 | ARG fastlane_version 133 | 134 | RUN bundle init \ 135 | && bundle add --version "$fastlane_version" fastlane 136 | 137 | #----------------------------------------------- 138 | #----------------------------------------------- 139 | #----------------------------------------------- 140 | 141 | FROM fastlane AS android 142 | 143 | SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] 144 | 145 | # TODO: Get JAVA_HOME dinamically from a JDK binary 146 | # TODO: Use `dirname $(dirname $(readlink -f $(which javac)))` after the following issue is fixed 147 | # TODO: https://github.com/moby/moby/issues/29110 148 | ENV ANDROID_HOME="$SDK_ROOT/android-sdk" \ 149 | JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 150 | ENV PATH="$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$HOME/.local/bin" 151 | 152 | # renovate: release=bullseye depName=openjdk-17-jdk-headless 153 | ARG OPENJDK_17_JDK_HEADLESS_VERSION="17.0.15+6-1~deb12u1" 154 | # renovate: release=bullseye depName=sudo 155 | ARG SUDO_VERSION="1.9.13p3-1+deb12u1" 156 | 157 | USER root 158 | RUN apt-get update \ 159 | && apt-get install -y --no-install-recommends \ 160 | # For Android x86 emulators 161 | # libxtst6=2:1.2.3-1build4 \ 162 | # libnss3-dev=2:3.68.2-0ubuntu1.1 \ 163 | # libnspr4=2:4.32-3build1 \ 164 | # libxss1=1:1.2.3-1build2 \ 165 | # libasound2=1.2.6.1-1ubuntu1 \ 166 | # libatk-bridge2.0-0=2.38.0-3 \ 167 | # libgtk-3-0=3.24.33-1ubuntu2 \ 168 | # libgdk-pixbuf2.0-0=2.40.2-2build4 \ 169 | # Android SDK dependencies 170 | ## JDK needs to be used instead of JRE because it provides the jlink tool used by the Android build 171 | openjdk-17-jdk-headless="$OPENJDK_17_JDK_HEADLESS_VERSION" \ 172 | # To allow changing ownership in GitLab CI /builds 173 | sudo="$SUDO_VERSION" \ 174 | && rm -rf /var/lib/apt/lists/* \ 175 | # To allow changing ownership in GitLab CI /builds 176 | && echo "flutter ALL= NOPASSWD:/bin/chown -R flutter /builds, /bin/chown -R flutter /builds/*" >> /etc/sudoers.d/flutter 177 | 178 | USER flutter:flutter 179 | WORKDIR "$HOME" 180 | 181 | ARG android_build_tools_version 182 | ARG android_platform_versions 183 | ARG android_ndk_version 184 | ARG cmake_version 185 | 186 | RUN mkdir -p "$ANDROID_HOME" \ 187 | && chown -R flutter:flutter "$ANDROID_HOME" \ 188 | && command_line_tools_url="$(curl -s https://developer.android.com/studio/ | grep -o 'https://dl.google.com/android/repository/commandlinetools-linux-[0-9]\+_latest.zip')" \ 189 | && curl -o android-cmdline-tools.zip "$command_line_tools_url" \ 190 | && mkdir -p "$ANDROID_HOME/cmdline-tools/" \ 191 | && unzip -q android-cmdline-tools.zip -d "$ANDROID_HOME/cmdline-tools/" \ 192 | && mv "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/latest" \ 193 | && rm android-cmdline-tools.zip \ 194 | # Installing deprecated Android SDK Tools (revision: 26.1.1) 195 | # Because Flutter always downloads it, even when it's not necessary, with log: "Install Android SDK Tools (revision: 26.1.1)" 196 | # && curl -o android-sdk-tools.zip https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip \ 197 | # && mkdir -p "$ANDROID_HOME/" \ 198 | # && unzip -q android-sdk-tools.zip -d "$ANDROID_HOME/" \ 199 | # && rm android-sdk-tools.zip \ 200 | && (yes || true) | sdkmanager --licenses \ 201 | # && mkdir -p "$HOME/.local/bin" \ 202 | # && curl -o "$HOME/.local/bin/android-wait-for-emulator" https://raw.githubusercontent.com/travis-ci/travis-cookbooks/master/community-cookbooks/android-sdk/files/default/android-wait-for-emulator \ 203 | # && chmod +x "$HOME/.local/bin/android-wait-for-emulator" \ 204 | && touch "$HOME/.android/repositories.cfg" \ 205 | # && sdkmanager platform-tools \ 206 | && mkdir -p "$HOME/.android" \ 207 | # && touch "$HOME/.android/repositories.cfg" \ 208 | # && if [ "$(uname -m)" = "x86_64" ] ; then sdkmanager emulator ; fi \ 209 | && sdkmanager --update \ 210 | && (yes || true) | sdkmanager \ 211 | "platform-tools" \ 212 | "build-tools;$android_build_tools_version" \ 213 | "ndk;$android_ndk_version" \ 214 | "cmake;$cmake_version" \ 215 | && for version in $android_platform_versions; do (yes || true) | sdkmanager "platforms;android-$version"; done \ 216 | && flutter config --enable-android \ 217 | && (yes || true) | flutter doctor --android-licenses \ 218 | && flutter precache --android \ 219 | && flutter create build_app 220 | 221 | WORKDIR "$HOME/build_app/android" 222 | RUN ./gradlew --version 223 | 224 | WORKDIR "$HOME" 225 | RUN rm -r build_app 226 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [3.32.2] - 2025-06-05 6 | 7 | ### ⚙️ Miscellaneous Tasks 8 | 9 | - Split into tag.yml and changelog.yml workflows (#347) 10 | - *(release)* Update flutter dependencies in version.json for 3.32.2 (#348) 11 | 12 | ## [3.32.1] - 2025-05-30 13 | 14 | ### ⚙️ Miscellaneous Tasks 15 | 16 | - *(release)* Update flutter dependencies in version.json for 3.32.1 (#345) 17 | 18 | ## [3.32.0] - 2025-05-23 19 | 20 | ### ⚙️ Miscellaneous Tasks 21 | 22 | - Generate changelog with git-cliff (#330) 23 | - Set tools digest to verify integrity (#331) 24 | - Download immutable artifact by id (#337) 25 | - Update artifact download configuration (#342) 26 | - *(release)* Update flutter dependencies in version.json for 3.32.0 (#343) 27 | 28 | ## [3.29.3] - 2025-04-17 29 | 30 | ### 🚀 Features 31 | 32 | - Build windows image (#314) 33 | 34 | ### 🐛 Bug Fixes 35 | 36 | - *(deps)* Update dependency mdx-to-md to ^0.5.0 (#324) 37 | 38 | ### 💼 Other 39 | 40 | - *(deps)* Bump @babel/runtime (#312) 41 | - Update windows image to ltsc2025 (#317) 42 | - *(deps)* Bump estree-util-value-to-estree from 3.3.2 to 3.3.3 in /docs/src in the npm_and_yarn group across 1 directory (#325) 43 | 44 | ### 📚 Documentation 45 | 46 | - Add table of contents and image table (#323) 47 | 48 | ### ⚙️ Miscellaneous Tasks 49 | 50 | - Single workflow to update versions (#311) 51 | - Get version from parsed JSON (#313) 52 | - Schedule GitHub Actions updates on the first day of the month (#318) 53 | - Upgrade artifact actions to use digest (#319) 54 | - Grant app token only current repository (#320) 55 | - Download-artifact can not overwrite existing files (#327) 56 | - Path is a folder in download-artifact (#328) 57 | - Update flutter dependencies in version.json for 3.29.3 (#329) 58 | 59 | ## [3.29.2] - 2025-03-15 60 | 61 | ### ⚙️ Miscellaneous Tasks 62 | 63 | - Generate tag with Github App token to trigger Actions (#305) 64 | - Run pr build only from latest commit (#306) 65 | - Upgrade actions only for new major or minor versions (#308) 66 | - Update flutter version in flutter_version.json to 3.29.2 (#309) 67 | - Update flutter dependencies in version.json for 3.29.2 (#310) 68 | 69 | ## [3.29.1] - 2025-03-09 70 | 71 | ### 🐛 Bug Fixes 72 | 73 | - Use github context because octokit is not available (#293) 74 | 75 | ### 💼 Other 76 | 77 | - Replace yq with cue to reduce tool dependencies (#296) 78 | 79 | ### 📚 Documentation 80 | 81 | - Mention Flutter license (#301) 82 | 83 | ### ⚙️ Miscellaneous Tasks 84 | 85 | - Split ci and release workflows (#291) 86 | - Checkout repository (#292) 87 | - Read environment variables in create_git_tag (#294) 88 | - Define VERSION_MANIFEST at workflow level (#295) 89 | - Replace jq with cue to reduce tool dependencies (#297) 90 | - Use deb renovate datasource instead of repology (#300) 91 | - Update flutter version in flutter_version.json to 3.29.1 (#302) 92 | - Discard changes to flutter source code when switching tags (#303) 93 | - Update flutter dependencies in version.json for 3.29.1 (#304) 94 | 95 | ## [3.29.0] - 2025-02-17 96 | 97 | ### 🐛 Bug Fixes 98 | 99 | - Update version.json path 100 | - Remove annotation CompileDynamic 101 | - Remove ecr registry 102 | - Don't print message on entrypoint to allow initial calls from CI systems (#155) 103 | 104 | ### 💼 Other 105 | 106 | - Move Dockerfile to root 107 | - Remove locale env and update regex and update git version 108 | - Create flutter base image and then android 109 | - Set non-root user as flutter 110 | - Flutter downloads obsolete Android SDK Tools (revision: 26.1.1) 111 | - Add entrypoint to change ownership of CI_PROJECT_DIR 112 | - Leave sudo but remove entrypoint 113 | - Add logical and before modifying sudoers 114 | - Add pattern /builds/* to sudoers 115 | - Add image opencontainers labels 116 | - Set JAVA_HOME 117 | - Explicitly set java home 118 | - Join env statements 119 | - Add multiple platform versions 120 | - Use platforms_versions 121 | - Do not quote array of arguments in build args 122 | - Upgrade curl to 7.81.0-1ubuntu1.8 123 | - Upgrade openjdk-11-jdk to 11.0.18+10-0ubuntu1~22.04 and sudo to 1.9.9-1ubuntu2.2 124 | - Add ENABLE_ANALYTICS to entrypoint 125 | - Upgrade curl to 7.81.0-1ubuntu1.10 126 | - Update sudo to 1.9.9-1ubuntu2.4 127 | - Add repology source ubuntu 22:04 128 | - Remove os specifc versioning 129 | - Fix typo between curl and git 130 | - Fix ubuntu package names 131 | - Upgrade git to 2.34.1-1ubuntu1.8 132 | - Add args for openjdk and sudo 133 | - Make entrypoint executable 134 | - Copy entrypoint with flutter user permissions 135 | - Upgrade openjdk-11-jdk to 11.0.19+7~us1-0ubuntu1~22.04.1 136 | - Chmod entrypoint 137 | - Migrate to openjdk-11-jdk-headless 138 | - Migrate to JRE with openjdk-11-jre-headless 139 | - Restore openjdk-11-jdk-headless 140 | - Uncomment flutter installation 141 | - Switch to debian/debian:11-slim 142 | - Add cross-env 143 | - Add fastlane stage 144 | - Install fastlane with bundler 145 | - Update dependencies versions in manifest with flutter 3.13.0' (#33) 146 | - Upgrade to openjdk 17 to 17.0.7+7-1~deb11u1 (#37) 147 | - Upgrade to debian 12 (#78) 148 | - Change debian registry to docker hub (#90) 149 | - Upgrade openjdk-17-jdk-headless to 17.0.10+7-1~deb12u1 (#158) 150 | - Join parsed platform versions with space 151 | - *(deps)* Bump braces (#196) 152 | - *(deps)* Bump cross-spawn from 7.0.3 to 7.0.6 in /docs/src in the npm_and_yarn group across 1 directory (#267) 153 | - *(deps)* Bump esbuild (#285) 154 | - Remove --depth 1 from git clone in Dockerfile (#287) 155 | 156 | ### 🚜 Refactor 157 | 158 | - Format version.json with prettier 159 | - Update renovate according to validator (#122) 160 | - Migrate Android version update script to Kotlin DSL and remove Groovy version (#288) 161 | 162 | ### 📚 Documentation 163 | 164 | - Add todo to get latest versions 165 | - Clarify readme 166 | - Leave registry link only 167 | - Add mdx readme 168 | - Update readme.mdx 169 | - Add license 170 | - Add url to badges 171 | - Delete images.json 172 | - Reorganize readme 173 | - Mention gitlab ci yaml 174 | - Render docs 175 | - Update tool versions 176 | - Rename usage to getting started 177 | - Add source repository 178 | - Reorganize readme 179 | - Add interpolating expressions and className to code blocks 180 | - Replace triple backtick with pre code block to remove exceeding line 181 | - Delete unused sha from readme 182 | - Explain more why not latest 183 | - Split readme and ecr about 184 | - Add fastlane related project 185 | - Change wording of related projects 186 | - Remove todo URLs from Dockerfile 187 | - Add command to render both docs 188 | - Add channel badge 189 | - Update android badges 190 | - Add space after first badge 191 | - Use .com github domain 192 | - Group sections related to features (#42) 193 | - Update documents (#233) 194 | - Update license path (#234) 195 | - Add a security policy (#238) 196 | - Add openssf scorecard (#241) 197 | - Reorganize sections in readme.md (#264) 198 | 199 | ### 🧪 Testing 200 | 201 | - Add test_app 202 | - Add test commands for downloads 203 | - Increase timeout to 4m 204 | - Verify analytics are disabled 205 | - Check dart and flutter analytics are disabled 206 | - Fastlane can run lanes 207 | - Update expected android sdk command line tools to version 11.0 (#38) 208 | - Gradle can have a patch version 209 | - Platforms can have multiple versions 210 | 211 | ### ⚙️ Miscellaneous Tasks 212 | 213 | - Add example workflow 214 | - Sync after commit in vscode 215 | - Move scripts to a new directory 216 | - Build and push to ecr 217 | - Add variable IMAGE_REPOSITORY_TAG 218 | - Update scripts 219 | - Give write permission to packages to github token 220 | - Give read permission to contents to github token 221 | - Use variables for container registries 222 | - Use kaniko to build and push 223 | - Upgrade flutter to 3.7.3 224 | - Add --use-new-run to kaniko 225 | - Use --snapshotMode=redo in kaniko 226 | - Upgrade flutter to 3.7.4 227 | - Add env variables FLUTTER_VERSION and ANDROID_BUILD_TOOLS_VERSION 228 | - Add env variable PLATFORMS_VERSIONS 229 | - Read version json 230 | - Read version.json 231 | - Add outputs 232 | - Format echo 233 | - Use release version in action zoexx/github-action-json-file-properties 234 | - Echo all outputs 235 | - Print all outputs 236 | - Output only flutter 237 | - FromJson version and commit 238 | - Use fromJson in flutter_version 239 | - Add github action for graphql 240 | - Updating github-token to GH_API_TOKEN 241 | - Log more output 242 | - Keep only latest tag 243 | - Unescape regex 244 | - Write latest tag to file 245 | - Add property node 246 | - Read current version json 247 | - Create pull request 248 | - Add permissions for create pull request 249 | - Add flutter version to tag 250 | - Add variable env.FLUTTER_VERSION 251 | - Setup flutter 252 | - Use fromJson 253 | - Create test app 254 | - Running gradlew 255 | - Add extension to updateAndroidPlatform.gradle 256 | - Use forward slash for path separator 257 | - Restore create pull request 258 | - Clean test app 259 | - Run on every day 260 | - Push to docker hub 261 | - Push to quay 262 | - Load image metadata with docker/metadata-action 263 | - Use raw tags in metadata 264 | - Get last 20 tags to increase change of matching regex 265 | - Add renovate 266 | - Change ENV to ARG in renovate 267 | - Disable docker major updates 268 | - Disable docker minor update 269 | - Pin version of ca-certificates 270 | - Add version epoch to git ubuntu version 271 | - Add environment variable GITHUB_SHORT_SHA 272 | - Use snapshotMode redo in kaniko 273 | - Update openjdk-11-jre-headless in renovate annotation 274 | - Update gradle version 275 | - Rename gradle script to updateAndroidVersions 276 | - Delete unused test_app 277 | - Show platform versions 278 | - Use jq to extract variables from version.json 279 | - Add xargs to convert multiline string to string with spaces 280 | - Migrate to docker/build-push-action to allow testing image 281 | - Setup buildx with docker/setup-buildx-action 282 | - Use ghcr for image cache 283 | - Test image structure 284 | - Add build args and cache to local docker image 285 | - Setup docker buildx before testing image 286 | - Add target android 287 | - Change path triggers 288 | - Update docs after version 289 | - Set the docs path to docs/src 290 | - Add npm cache to documentation update job 291 | - Change setup-node path 292 | - Change working directory for update android versions 293 | - Update docker hub description 294 | - Fix gradle script path 295 | - Update ecr repository description 296 | - Use preinstalled jq in github actions 297 | - Remove exceeding single quote 298 | - Remove sha from tag 299 | - Export flutter version from javascript 300 | - Check in which channel the tag exists 301 | - Remove semicolon 302 | - Move github script to script directory 303 | - Fix typo in script directory 304 | - Reorganize files to clean root directory 305 | - Add variable CACHE_REPOSITORY_PATH 306 | - Rename android test to bundle test 307 | - Update fastlane version 308 | - Log version 309 | - Await json 310 | - Initialize data in js 311 | - Require fs 312 | - Increase tags returned from query to 60 313 | - Add flutter-version to renovate.json 314 | - Add flutter regex to renovate 315 | - Use recursive matchStringsStrategy for flutter-version 316 | - Escape dot in fileMatch regex 317 | - Set config directory for flutter version 318 | - Remove recursive strategy from renovate 319 | - Split update workflow into flutter and dependencies 320 | - Declare version variable 321 | - Add workflow_dispatch trigger 322 | - Correct flutter version to 3.10.6 323 | - Update trigger to flutter_version 324 | - Run update_flutter_dependencies after pr is merged 325 | - Change automatic pr title 326 | - Add other trigger to job if 327 | - Move paths to pull request event (#31) 328 | - Override version json with flutter version (#32) 329 | - Use gitsign to sign commits in github workflows (#34) 330 | - Add tag chainguard-dev/actions/setup-gitsign@main (#35) 331 | - Update openjdk11 to 11.0.20+8-1~deb11u1 (#36) 332 | - Use commit sha for github action versions (#39) 333 | - Trigger workflow on push to main instead of pr closed (#41) 334 | - Search in releases json file instead of github query (#43) 335 | - LinuxReleasesResponse variable (#44) 336 | - Use volta to reproduce nodejs version (#45) 337 | - Get node version from package.json (#47) 338 | - Merge old and new maps in gradle (#48) 339 | - Use putAll to merge maps (#49) 340 | - Validate json schema with cue (#50) 341 | - Update dependencies versions in manifest with flutter 3.13.1 (#51) 342 | - Update dependencies versions in manifest with flutter 3.13.1 (#54) 343 | - Remove quote from pr title (#53) 344 | - Update dependencies versions in manifest with flutter 3.13.2 (#57) 345 | - Update dependencies versions in manifest with flutter 3.13.2 (#58) 346 | - Update dependencies versions in manifest with flutter 3.13.3 (#62) 347 | - Update dependencies versions in manifest with flutter 3.13.3 (#64) 348 | - Pin cue-lang/setup-cue action to digest (#66) 349 | - Update dependencies versions in manifest with flutter 3.13.4 (#72) 350 | - Update dependencies versions in manifest with flutter 3.13.4 (#73) 351 | - Add workflow for changes that affect the dockerfile (#77) 352 | - Automerge chainguard digest changes (#79) 353 | - Update dependencies versions in manifest with flutter 3.13.4 (#80) 354 | - Change action host os to ubuntu-22.04 (#81) 355 | - Change setup-flutter action to follow tag v2.2 (#82) 356 | - Update dependencies versions in manifest with flutter 3.13.5 (#86) 357 | - Update dependencies versions in manifest with flutter 3.13.5 (#87) 358 | - Ignore .vscode folder (#89) 359 | - Add renovate groups (#94) 360 | - Update dependencies versions in manifest with flutter 3.13.6 (#95) 361 | - Update dependencies versions in manifest with flutter 3.13.6 (#96) 362 | - Rename jobs to separate status checks (#97) 363 | - Update path of readme.md (#100) 364 | - Update dependencies versions in manifest with flutter 3.13.7 (#101) 365 | - Update dependencies versions in manifest with flutter 3.13.7 (#102) 366 | - Update pull request titles created with action (#103) 367 | - Update flutter version in flutter_version.json to 3.13.8 (#107) 368 | - Use GH_APP_TOKEN to trigger workflows on created pull requests (#109) 369 | - Update flutter dependencies in version.json for 3.13.8 (#108) 370 | - Update flutter version in flutter_version.json to 3.13.9 (#112) 371 | - Update flutter dependencies in version.json for 3.13.9 (#113) 372 | - Update flutter version in flutter_version.json to 3.16.0 (#120) 373 | - Update flutter dependencies in version.json for 3.16.0 (#121) 374 | - Update flutter version in flutter_version.json to 3.16.1 (#129) 375 | - Update flutter dependencies in version.json for 3.16.1 (#130) 376 | - Update flutter version in flutter_version.json to 3.16.2 (#131) 377 | - Update flutter dependencies in version.json for 3.16.2 (#132) 378 | - Run renovate monthly (#134) 379 | - Update flutter version in flutter_version.json to 3.16.3 (#135) 380 | - Update flutter dependencies in version.json for 3.16.3 (#136) 381 | - Update flutter version in flutter_version.json to 3.16.4 (#137) 382 | - Update flutter dependencies in version.json for 3.16.4 (#138) 383 | - Update flutter version in flutter_version.json to 3.16.5 (#139) 384 | - Update flutter dependencies in version.json for 3.16.5 (#140) 385 | - Update flutter version in flutter_version.json to 3.16.6 (#143) 386 | - Update flutter dependencies in version.json for 3.16.6 (#144) 387 | - Update flutter version in flutter_version.json to 3.16.7 (#145) 388 | - Update flutter dependencies in version.json for 3.16.7 (#146) 389 | - Update flutter version in flutter_version.json to 3.16.8 (#147) 390 | - Update flutter dependencies in version.json for 3.16.8 (#148) 391 | - Update flutter version in flutter_version.json to 3.16.9 (#149) 392 | - Update flutter dependencies in version.json for 3.16.9 (#150) 393 | - Run build if entrypoint changes (#156) 394 | - Split config validation (#157) 395 | - Check if files were changed (#159) 396 | - Update flutter version in flutter_version.json to 3.19.0 (#160) 397 | - Update flutter dependencies in version.json for 3.19.0 (#163) 398 | - Update flutter version in flutter_version.json to 3.19.1 (#165) 399 | - Update flutter dependencies in version.json for 3.19.1 (#166) 400 | - Update flutter version in flutter_version.json to 3.19.2 (#167) 401 | - Update flutter dependencies in version.json for 3.19.2 (#168) 402 | - Update cron schedule to run only on weekdays (#173) 403 | - Update flutter version in flutter_version.json to 3.19.3 (#174) 404 | - Update flutter dependencies in version.json for 3.19.3 (#175) 405 | - Update flutter version in flutter_version.json to 3.19.4 (#176) 406 | - Update flutter dependencies in version.json for 3.19.4 (#177) 407 | - Update flutter version in flutter_version.json to 3.19.5 (#178) 408 | - Update flutter dependencies in version.json for 3.19.5 (#179) 409 | - Update flutter version in flutter_version.json to 3.19.6 (#182) 410 | - Update flutter dependencies in version.json for 3.19.6 (#183) 411 | - Update flutter version in flutter_version.json to 3.22.0 (#186) 412 | - Update flutter dependencies in version.json for 3.22.0 (#187) 413 | - Update flutter version in flutter_version.json to 3.22.1 (#188) 414 | - Update flutter dependencies in version.json for 3.22.1 (#189) 415 | - Update flutter version in flutter_version.json to 3.22.2 (#192) 416 | - Update flutter dependencies in version.json for 3.22.2 (#193) 417 | - Update flutter dependencies in version.json for 3.22.2 (#197) 418 | - Update flutter version in flutter_version.json to 3.22.3 (#202) 419 | - Update flutter dependencies in version.json for 3.22.3 (#203) 420 | - Update fastlane in version.json for 3.22.3 (#206) 421 | - Upgrade peter-evans/create-pull-request to v6 (#207) 422 | - Upgrade cue-lang/setup-cue to v1.0.1 (#208) 423 | - Upgrade cue-lang/setup-cue to v1.0.1 in other workflows (#209) 424 | - Update flutter version in flutter_version.json to 3.24.0 (#210) 425 | - Update flutter dependencies in version.json for 3.24.0 (#211) 426 | - Update flutter version in flutter_version.json to 3.24.1 (#212) 427 | - Update flutter dependencies in version.json for 3.24.1 (#213) 428 | - Use github integration for docker buildx cache (#218) 429 | - Add docker/scout-action to compare differences (#219) 430 | - Record only docker hub image (#220) 431 | - Scout compare (#221) 432 | - Pin docker/scount-action (#226) 433 | - Update flutter version in flutter_version.json to 3.24.2 (#227) 434 | - Run job in ghcr.io/gmeligio/flutter-android image (#228) 435 | - Update flutter dependencies in version.json for 3.24.2 (#229) 436 | - Update repo flutter version after pushing new image (#230) 437 | - Update flutter version in flutter_version.json to 3.24.3 (#231) 438 | - Update flutter dependencies in version.json for 3.24.3 (#232) 439 | - Add scorecard (#235) 440 | - Set default permission to contents:read (#236) 441 | - Add CODEOWNERS (#237) 442 | - Upload docker hub CVEs to code scanning (#239) 443 | - Pin yq action with sha (#240) 444 | - Show only fixable CVEs (#242) 445 | - Update flutter dependencies in version.json for 3.24.3 (#247) 446 | - Unify PR workflows into build.yml (#248) 447 | - Rename build_and_push workflow to release (#249) 448 | - Update flutter dependencies in version.json for 3.24.3 (#250) 449 | - Update flutter version in flutter_version.json to 3.24.4 (#251) 450 | - Update flutter dependencies in version.json for 3.24.4 (#252) 451 | - Run renovate weekly to keep low noise with prHourlyLimit 2 (#255) 452 | - Update flutter version in flutter_version.json to 3.24.5 (#262) 453 | - Update flutter dependencies in version.json for 3.24.5 (#263) 454 | - Update flutter version in flutter_version.json to 3.27.0 (#270) 455 | - Update flutter dependencies in version.json for 3.27.0 (#271) 456 | - Update flutter version in flutter_version.json to 3.27.1 (#272) 457 | - Update flutter dependencies in version.json for 3.27.1 (#273) 458 | - Update flutter version in flutter_version.json to 3.27.2 (#276) 459 | - Update flutter dependencies in version.json for 3.27.2 (#277) 460 | - Update flutter version in flutter_version.json to 3.27.3 (#279) 461 | - Update flutter dependencies in version.json for 3.27.3 (#280) 462 | - Update flutter version in flutter_version.json to 3.27.4 (#282) 463 | - Update flutter dependencies in version.json for 3.27.4 (#283) 464 | - Update flutter version in flutter_version.json to 3.29.0 (#286) 465 | - Update flutter dependencies in version.json for 3.29.0 (#289) 466 | 467 | 468 | -------------------------------------------------------------------------------- /config/android.cue: -------------------------------------------------------------------------------- 1 | #FileContentTests: { 2 | name: string 3 | path: _ 4 | expectedContents: [string] 5 | } 6 | 7 | #ContainerStructureTest: { 8 | schemaVersion: _ 9 | commandTests: _ 10 | fileContentTests: [...#FileContentTests] 11 | } 12 | 13 | input: #ContainerStructureTest 14 | 15 | android_cmdline_tools_version: string @tag(android_cmdline_tools_version) 16 | android_cmdline_tools_test_expected_content: string @tag(android_cmdline_tools_test_expected_content) 17 | 18 | output: { 19 | schemaVersion: input.schemaVersion 20 | commandTests: input.commandTests 21 | fileContentTests: [ 22 | { 23 | name: "Android SDK Command-line Tools is version \(android_cmdline_tools_version)" 24 | path: input.fileContentTests[0].path 25 | expectedContents: [android_cmdline_tools_test_expected_content] 26 | }, 27 | input.fileContentTests[1] 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /config/flutter_version.cue: -------------------------------------------------------------------------------- 1 | import "strings" 2 | import "list" 3 | 4 | #Version3: { 5 | version!: =~ "^\\d+.\\d+.\\d+$" 6 | } 7 | 8 | flutter: { 9 | channel!: "stable" | "beta" 10 | commit!: strings.MaxRunes(40) 11 | #Version3 12 | } 13 | -------------------------------------------------------------------------------- /config/flutter_version.json: -------------------------------------------------------------------------------- 1 | { 2 | "flutter": { 3 | "channel": "stable", 4 | "commit": "b25305a8832cfc6ba632a7f87ad455e319dccce8", 5 | "version": "3.32.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /config/version.cue: -------------------------------------------------------------------------------- 1 | import "strings" 2 | import "list" 3 | 4 | #PlatformVersion: { 5 | version!: int 6 | } 7 | 8 | #MinorVersion: { 9 | version!: =~ "^\\d+.\\d+$" 10 | } 11 | 12 | #PatchVersion: { 13 | version!: =~ "^\\d+.\\d+.\\d+$" 14 | } 15 | 16 | #FlutterVersion: { 17 | flutter: { 18 | channel!: "stable" | "beta" 19 | commit!: strings.MaxRunes(40) 20 | #PatchVersion 21 | } 22 | } 23 | 24 | #MinorOrPatchVersion: #MinorVersion | #PatchVersion 25 | 26 | #Version: { 27 | #FlutterVersion 28 | 29 | android: { 30 | platforms!: [...#PlatformVersion] & list.MinItems(1) & list.UniqueItems 31 | gradle!: #MinorOrPatchVersion 32 | buildTools!: #PatchVersion 33 | cmdlineTools!: #MinorVersion 34 | ndk!: #PatchVersion 35 | cmake!: #PatchVersion 36 | } 37 | 38 | fastlane!: #PatchVersion 39 | } 40 | -------------------------------------------------------------------------------- /config/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "flutter": { 3 | "channel": "stable", 4 | "commit": "8defaa71a77c16e8547abdbfad2053ce3a6e2d5b", 5 | "version": "3.32.2" 6 | }, 7 | "android": { 8 | "platforms": [ 9 | { 10 | "version": 35 11 | } 12 | ], 13 | "gradle": { 14 | "version": "8.12" 15 | }, 16 | "buildTools": { 17 | "version": "34.0.0" 18 | }, 19 | "cmdlineTools": { 20 | "version": "19.0" 21 | }, 22 | "ndk": { 23 | "version": "26.3.11579264" 24 | }, 25 | "cmake": { 26 | "version": "3.22.1" 27 | } 28 | }, 29 | "fastlane": { 30 | "version": "2.227.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | flutter: 3 | build: 4 | dockerfile: ./android.Dockerfile 5 | target: flutter 6 | args: 7 | flutter_version: $FLUTTER_VERSION 8 | environment: 9 | ENABLE_ANALYTICS: $ENABLE_ANALYTICS 10 | 11 | fastlane: 12 | build: 13 | target: fastlane 14 | args: 15 | flutter_version: $FLUTTER_VERSION 16 | fastlane_version: $FASTLANE_VERSION 17 | environment: 18 | ENABLE_ANALYTICS: $ENABLE_ANALYTICS 19 | 20 | android: 21 | build: 22 | dockerfile: ./android.Dockerfile 23 | target: android 24 | args: 25 | flutter_version: $FLUTTER_VERSION 26 | fastlane_version: $FASTLANE_VERSION 27 | android_build_tools_version: $ANDROID_BUILD_TOOLS_VERSION 28 | android_platform_versions: $ANDROID_PLATFORM_VERSIONS 29 | android_ndk_version: $ANDROID_NDK_VERSION 30 | cmake_version: $CMAKE_VERSION 31 | environment: 32 | ENABLE_ANALYTICS: $ENABLE_ANALYTICS 33 | 34 | windows: 35 | build: 36 | dockerfile: ./windows.Dockerfile 37 | args: 38 | flutter_version: $FLUTTER_VERSION 39 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Contributing 4 | 5 | ## Adding new Github Actions 6 | 7 | When adding new Github Actions the `.github\renovate.json` needs to be checked and add the new action to: 8 | 9 | * the automerge array if it's not an important action 10 | 11 | ### Dockerfile stages 12 | 13 | 1. `flutter` stage hast only the dependencies required to install flutter and common tools used by flutter internal commands, like `git`. 14 | 2. `fastlane` stage has the dependencies required to install fastlane but doesn't install fastlane. 15 | 3. `android` stage has the dependencies required to install the Android SDK and to develop Flutter apps for Android. -------------------------------------------------------------------------------- /docs/src/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /docs/src/badges.mdx: -------------------------------------------------------------------------------- 1 | import * as version from '../../config/version.json' 2 | export const flutterChannel = version.flutter.channel 3 | export const channelColor = { 4 | stable: "blue", 5 | beta: "blueviolet", 6 | } 7 | 8 | export const channelUrl = 'https://docs.flutter.dev/release/archive?tab=linux'; 9 | export const channelBadgeUrl = `https://img.shields.io/static/v1?label=${encodeURIComponent('channel')}&message=${encodeURIComponent(flutterChannel)}&color=${encodeURIComponent(channelColor[flutterChannel])}`; 10 | 11 | [![openssf scorecard](https://api.scorecard.dev/projects/github.com/gmeligio/flutter-docker-image/badge)](https://scorecard.dev/viewer/?uri=github.com/gmeligio/flutter-docker-image) 12 | channel [![flutter-android version](https://img.shields.io/docker/v/gmeligio/flutter-android?label=flutter-android%20version)](https://hub.docker.com/r/gmeligio/flutter-android/tags) 13 | [![flutter-android pulls](https://img.shields.io/docker/pulls/gmeligio/flutter-android?label=flutter-android%20pulls)](https://hub.docker.com/r/gmeligio/flutter-android/tags) 14 | -------------------------------------------------------------------------------- /docs/src/compile.js: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'node:fs/promises' 2 | import { mdxToMd } from 'mdx-to-md' 3 | import { resolve } from 'node:path' 4 | import remarkGfm from 'remark-gfm' 5 | import remarkToc from 'remark-toc' 6 | 7 | /** 8 | * @see https://github.com/kentcdodds/mdx-bundler?tab=readme-ov-file#mdxoptions 9 | */ 10 | function mdxOptions(options) { 11 | options.remarkPlugins = [ 12 | ...(options.remarkPlugins ?? []), 13 | remarkGfm, 14 | remarkToc, 15 | ] 16 | 17 | return options 18 | } 19 | 20 | const args = process.argv.slice(2) 21 | const sourceRelativePath = args[0] 22 | const outputRelativePath = args[1] 23 | const markdown = await mdxToMd(resolve(sourceRelativePath), { 24 | mdxOptions, 25 | }) 26 | const banner = `This markdown file was auto-generated from "${sourceRelativePath}"` 27 | const readme = `\n\n${markdown}` 28 | 29 | await writeFile(outputRelativePath, readme) 30 | 31 | console.log(`📝 Converted ${sourceRelativePath} -> ${outputRelativePath}`) 32 | -------------------------------------------------------------------------------- /docs/src/content.mdx: -------------------------------------------------------------------------------- 1 | import * as versionJson from '../../config/version.json' 2 | export const flutterVersion = versionJson.flutter.version 3 | export const fastlaneVersion = versionJson.fastlane.version 4 | export const androidJson = versionJson.android 5 | export const gradleVersion = androidJson.gradle.version 6 | export const buildToolsVersion = androidJson.buildTools.version 7 | export const repositoryPath = 'gmeligio/flutter-android' 8 | export const dockerHubUri = `${repositoryPath}:${flutterVersion}` 9 | export const githubUri = `ghcr.io/${dockerHubUri}` 10 | export const quayUri = `quay.io/${dockerHubUri}` 11 | export const androidPlatformVersions = androidJson.platforms.map(p => p.version).join(', ') 12 | export const androidNdkVersion = androidJson.ndk.version 13 | export const dockerHubUrl = `https://hub.docker.com/r/${repositoryPath}` 14 | export const quayUrl = `https://quay.io/repository/${repositoryPath}` 15 | 16 | # Flutter Docker Image 17 | 18 | Docker images for Flutter Continuous Integration (CI). The source is available [on GitHub](https://github.com/gmeligio/flutter-docker-image). 19 | 20 | The images includes the minimum tools to run Flutter and build apps. The versions of the tools installed are based on the official [Flutter](https://github.com/flutter/flutter) repository. The final goal is that Flutter doesn't need to download anything like tools or SDKs when running the container. 21 | 22 | ## Contents 23 | 24 | ## Features 25 | 26 | - Installed Flutter SDK {flutterVersion}. 27 | - Analytics disabled by default, opt-in if `ENABLE_ANALYTICS` environment variable is passed when running the container. 28 | - Rootless user `flutter:flutter`, with permissions to run on Github workflows and GitLab CI. 29 | - Cached Fastlane gem {fastlaneVersion}. 30 | - Minimal image with predownloaded SDKs and tools ready to run `flutter` commands for the Android platform. 31 | 32 | Predownloaded SDKs and tools in Android: 33 | 34 | - Licenses accepted 35 | - Android SDK Platforms: {androidPlatformVersions} 36 | - Android NDK: {androidNdkVersion} 37 | - Gradle: {gradleVersion} 38 | 39 | ## Running Containers 40 | 41 | | Registry | flutter-android | 42 | |---------------------------|--------------------------------------------------------| 43 | | Docker Hub | {dockerHubUri} | 44 | | GitHub Container Registry | {githubUri} | 45 | | Quay | {quayUri} | 46 | 47 | On the terminal: 48 |

 49 | {`# From GitHub Container Registry
 50 | docker run --rm -it ${githubUri} bash`}
 51 | 
52 | 53 | On a workflow in GitHub Actions: 54 |

 55 | {`jobs:
 56 |     build:
 57 |       runs-on: ubuntu-22.04
 58 |       container:
 59 |         image: ${githubUri}
 60 |       steps:
 61 |         - name: Checkout
 62 |           uses: actions/checkout@v2
 63 |         - name: Build
 64 |           run: flutter build apk`}
 65 | 
66 | 67 | On a `.gitlab-ci.yml` in GitLab CI: 68 |

 69 | {`build:
 70 |     image: ${githubUri}
 71 |     script:
 72 |       - flutter build apk`}
 73 | 
74 | 75 | Fastlane: 76 |

 77 | {`# Ruby bundler is available in the container.
 78 | # The fastlane gem is cached but not installed
 79 | # For more information, see https://docs.fastlane.tools
 80 | 
 81 | # Use --prefer-local to download gems only if they are not cached
 82 | bundle install --prefer-local
 83 | bundle exec fastlane`}
 84 | 
85 | 86 | ## Tags 87 | 88 | Every new tag on the flutter stable channel gets built. The tag is composed of the Flutter version used to build the image: 89 | - Docker image: {dockerHubUri} 90 | - Flutter version: {flutterVersion} 91 | 92 | ## Building Locally 93 | 94 | The android.Dockerfile expects a few arguments: 95 | 96 | - `flutter_version `: The version of Flutter to use when building. Example: {flutterVersion} 97 | - `android_build_tools_version `: The version of the Android SDK Build Tools to install. Example: {buildToolsVersion} 98 | - `android_platform_versions `: The versions of the Android SDK Platforms to install, separated by spaces. Example: {androidPlatformVersions} 99 | 100 |

101 | {`# Android
102 | docker build --target android --build-arg flutter_version=${flutterVersion} --build-arg fastlane_version=${fastlaneVersion} --build-arg android_build_tools_version=${buildToolsVersion} --build-arg android_platform_versions="${androidPlatformVersions}" -t android-test .`}
103 | 
104 | 105 | ## Roadmap 106 | 107 | - Minimal image with predownloaded SDKs and tools ready to run `flutter` commands for the platforms: 108 | 109 | - iOS 110 | - Linux 111 | - Windows 112 | - Web 113 | 114 | - Android features: 115 | 116 | - Android emulator 117 | 118 | ## FAQ 119 | 120 | ### Why the images are not published in the AWS ECR Public registry? 121 | 122 | The storage of the images starts to cost after 50 GB and increases with every pushed image because the AWS Free Tier covers up to 50 GB of total storage for free in ECR Public. 123 | 124 | ## Why there is no dynamic tag like `latest`? 125 | 126 | There is no `latest` Docker tag on purpose. You need to specify the version of the image you want to use. The reason for that is that `latest` can cause unexpected behavior when rerunning a past CI job that was expected to use the old build of the `latest` tag. There are multiple articles explaining more about this reasoning like [What's Wrong With The Docker :latest Tag?](https://vsupalov.com/docker-latest-tag/) and [The misunderstood Docker tag: latest](https://medium.com/@mccode/the-misunderstood-docker-tag-latest-af3babfd6375). 127 | 128 | ## Contributing 129 | 130 | See [Contributing](docs/contributing.md). 131 | 132 | ## License 133 | 134 | Flutter is licensed under [BSD 3-Clause "New" or "Revised" license](https://github.com/flutter/flutter/blob/master/LICENSE). 135 | 136 | As with all Docker images, these likely also contain other software which may be under other licenses (such as Bash, etc from the base distribution, along with any direct or indirect dependencies of the primary software being contained). 137 | 138 | As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within. 139 | 140 | The [sources](https://github.com/gmeligio/flutter-docker-image) for producing {repositoryPath} Docker images are licensed under [MIT License](LICENSE.md). 141 | -------------------------------------------------------------------------------- /docs/src/contributing.mdx: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Adding new Github Actions 4 | 5 | When adding new Github Actions the `.github\renovate.json` needs to be checked and add the new action to: 6 | 7 | - the automerge array if it's not an important action 8 | 9 | ### Dockerfile stages 10 | 11 | 1. `flutter` stage hast only the dependencies required to install flutter and common tools used by flutter internal commands, like `git`. 12 | 2. `fastlane` stage has the dependencies required to install fastlane but doesn't install fastlane. 13 | 3. `android` stage has the dependencies required to install the Android SDK and to develop Flutter apps for Android. 14 | -------------------------------------------------------------------------------- /docs/src/license.mdx: -------------------------------------------------------------------------------- 1 | export const year = new Date().getFullYear() 2 | 3 | MIT License 4 | 5 | Copyright (c) 2023-{year} Eligio Alejandro Mariño Garcés 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /docs/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "doc", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "build": "npm run readme && npm run contributing && npm run license", 9 | "readme": "cross-env NODE_ENV=production node compile.js readme.mdx ../../readme.md", 10 | "license": "cross-env NODE_ENV=production node compile.js license.mdx ../../LICENSE.md", 11 | "contributing": "cross-env NODE_ENV=production node compile.js contributing.mdx ../contributing.md", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "cross-env": "^7.0.3", 18 | "mdx-to-md": "^0.5.0", 19 | "react": "^19.1.0", 20 | "react-dom": "^19.1.0", 21 | "remark-gfm": "^4.0.1", 22 | "remark-toc": "^9.0.0" 23 | }, 24 | "volta": { 25 | "node": "22.16.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/src/readme.mdx: -------------------------------------------------------------------------------- 1 | import Badges from './badges.mdx' 2 | import Content from './content.mdx' 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [![openssf scorecard](https://api.scorecard.dev/projects/github.com/gmeligio/flutter-docker-image/badge)](https://scorecard.dev/viewer/?uri=github.com/gmeligio/flutter-docker-image) [![channel](https://img.shields.io/static/v1?label=channel&message=stable&color=blue)](https://docs.flutter.dev/release/archive?tab=linux) [![flutter-android version](https://img.shields.io/docker/v/gmeligio/flutter-android?label=flutter-android%20version)](https://hub.docker.com/r/gmeligio/flutter-android/tags) [![flutter-android pulls](https://img.shields.io/docker/pulls/gmeligio/flutter-android?label=flutter-android%20pulls)](https://hub.docker.com/r/gmeligio/flutter-android/tags) 4 | 5 | # Flutter Docker Image 6 | 7 | Docker images for Flutter Continuous Integration (CI). The source is available [on GitHub](https://github.com/gmeligio/flutter-docker-image). 8 | 9 | The images includes the minimum tools to run Flutter and build apps. The versions of the tools installed are based on the official [Flutter](https://github.com/flutter/flutter) repository. The final goal is that Flutter doesn't need to download anything like tools or SDKs when running the container. 10 | 11 | ## Contents 12 | 13 | * [Features](#features) 14 | * [Running Containers](#running-containers) 15 | * [Tags](#tags) 16 | * [Building Locally](#building-locally) 17 | * [Roadmap](#roadmap) 18 | * [FAQ](#faq) 19 | * [Why the images are not published in the AWS ECR Public registry?](#why-the-images-are-not-published-in-the-aws-ecr-public-registry) 20 | * [Why there is no dynamic tag like latest?](#why-there-is-no-dynamic-tag-like-latest) 21 | * [Contributing](#contributing) 22 | * [License](#license) 23 | 24 | ## Features 25 | 26 | * Installed Flutter SDK 3.32.2. 27 | * Analytics disabled by default, opt-in if `ENABLE_ANALYTICS` environment variable is passed when running the container. 28 | * Rootless user `flutter:flutter`, with permissions to run on Github workflows and GitLab CI. 29 | * Cached Fastlane gem 2.227.2. 30 | * Minimal image with predownloaded SDKs and tools ready to run `flutter` commands for the Android platform. 31 | 32 | Predownloaded SDKs and tools in Android: 33 | 34 | * Licenses accepted 35 | * Android SDK Platforms: 35 36 | * Android NDK: 26.3.11579264 37 | * Gradle: 8.12 38 | 39 | ## Running Containers 40 | 41 | | Registry | flutter-android | 42 | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------- | 43 | | Docker Hub | [gmeligio/flutter-android:3.32.2](https://hub.docker.com/r/gmeligio/flutter-android) | 44 | | GitHub Container Registry | [ghcr.io/gmeligio/flutter-android:3.32.2](https://github.com/gmeligio/flutter-docker-image/pkgs/container/flutter-android) | 45 | | Quay | [quay.io/gmeligio/flutter-android:3.32.2](https://quay.io/repository/gmeligio/flutter-android) | 46 | 47 | On the terminal: 48 | 49 | ```bash 50 | # From GitHub Container Registry 51 | docker run --rm -it ghcr.io/gmeligio/flutter-android:3.32.2 bash 52 | ``` 53 | 54 | On a workflow in GitHub Actions: 55 | 56 | ```yaml 57 | jobs: 58 | build: 59 | runs-on: ubuntu-22.04 60 | container: 61 | image: ghcr.io/gmeligio/flutter-android:3.32.2 62 | steps: 63 | - name: Checkout 64 | uses: actions/checkout@v2 65 | - name: Build 66 | run: flutter build apk 67 | ``` 68 | 69 | On a `.gitlab-ci.yml` in GitLab CI: 70 | 71 | ```yaml 72 | build: 73 | image: ghcr.io/gmeligio/flutter-android:3.32.2 74 | script: 75 | - flutter build apk 76 | ``` 77 | 78 | Fastlane: 79 | 80 | ```bash 81 | # Ruby bundler is available in the container. 82 | # The fastlane gem is cached but not installed 83 | # For more information, see https://docs.fastlane.tools 84 | 85 | # Use --prefer-local to download gems only if they are not cached 86 | bundle install --prefer-local 87 | bundle exec fastlane 88 | ``` 89 | 90 | ## Tags 91 | 92 | Every new tag on the flutter stable channel gets built. The tag is composed of the Flutter version used to build the image: 93 | 94 | * Docker image: gmeligio/flutter-android:3.32.2 95 | * Flutter version: 3.32.2 96 | 97 | ## Building Locally 98 | 99 | The android.Dockerfile expects a few arguments: 100 | 101 | * `flutter_version `: The version of Flutter to use when building. Example: 3.32.2 102 | * `android_build_tools_version `: The version of the Android SDK Build Tools to install. Example: 34.0.0 103 | * `android_platform_versions `: The versions of the Android SDK Platforms to install, separated by spaces. Example: 35 104 | 105 | ```bash 106 | # Android 107 | docker build --target android --build-arg flutter_version=3.32.2 --build-arg fastlane_version=2.227.2 --build-arg android_build_tools_version=34.0.0 --build-arg android_platform_versions="35" -t android-test . 108 | ``` 109 | 110 | ## Roadmap 111 | 112 | * Minimal image with predownloaded SDKs and tools ready to run `flutter` commands for the platforms: 113 | * iOS 114 | * Linux 115 | * Windows 116 | * Web 117 | * Android features: 118 | * Android emulator 119 | 120 | ## FAQ 121 | 122 | ### Why the images are not published in the AWS ECR Public registry? 123 | 124 | The storage of the images starts to cost after 50 GB and increases with every pushed image because the AWS Free Tier covers up to 50 GB of total storage for free in ECR Public. 125 | 126 | ## Why there is no dynamic tag like `latest`? 127 | 128 | There is no `latest` Docker tag on purpose. You need to specify the version of the image you want to use. The reason for that is that `latest` can cause unexpected behavior when rerunning a past CI job that was expected to use the old build of the `latest` tag. There are multiple articles explaining more about this reasoning like [What's Wrong With The Docker :latest Tag?](https://vsupalov.com/docker-latest-tag/) and [The misunderstood Docker tag: latest](https://medium.com/@mccode/the-misunderstood-docker-tag-latest-af3babfd6375). 129 | 130 | ## Contributing 131 | 132 | See [Contributing](docs/contributing.md). 133 | 134 | ## License 135 | 136 | Flutter is licensed under [BSD 3-Clause "New" or "Revised" license](https://github.com/flutter/flutter/blob/master/LICENSE). 137 | 138 | As with all Docker images, these likely also contain other software which may be under other licenses (such as Bash, etc from the base distribution, along with any direct or indirect dependencies of the primary software being contained). 139 | 140 | As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within. 141 | 142 | The [sources](https://github.com/gmeligio/flutter-docker-image) for producing gmeligio/flutter-android Docker images are licensed under [MIT License](LICENSE.md). -------------------------------------------------------------------------------- /script/build_windows.sh: -------------------------------------------------------------------------------- 1 | # cmake generate 2 | cmake -S . -B ../build/windows/x64 -G "Visual Studio 16 2019" -A x64 -DFLUTTER_TARGET_PLATFORM=windows-x64 3 | 4 | # cmake build 5 | cmake --build ../build/windows/x64 --config Release --target INSTALL --verbose 6 | -------------------------------------------------------------------------------- /script/container_structure_test.sh: -------------------------------------------------------------------------------- 1 | container-structure-test test --image flutter-docker-image-android --config test/android.yml 2 | -------------------------------------------------------------------------------- /script/copyFlutterVersion.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | module.exports = async ({ core }) => { 5 | try { 6 | const flutterVersionPath = 'config/flutter_version.json' 7 | 8 | if ( 9 | !fs.existsSync(flutterVersionPath) || 10 | fs.lstatSync(flutterVersionPath).isDirectory() 11 | ) { 12 | throw new Error(`${flutterVersionPath} is missing or is a directory.`) 13 | } 14 | 15 | const flutterVersionData = fs.readFileSync(flutterVersionPath, 'utf8') 16 | const flutterVersionJson = JSON.parse(flutterVersionData) 17 | 18 | const versionPath = 'config/version.json' 19 | if ( 20 | !fs.existsSync(versionPath) || 21 | fs.lstatSync(versionPath).isDirectory() 22 | ) { 23 | throw new Error(`${versionPath} is missing or is a directory.`) 24 | } 25 | 26 | const versionData = fs.readFileSync(versionPath, 'utf8') 27 | let versionJson = JSON.parse(versionData) 28 | 29 | const resultPath = 'config/version.json' 30 | const result = { 31 | ...versionJson, 32 | ...flutterVersionJson, 33 | } 34 | 35 | const resultJson = JSON.stringify(result, null, 4) 36 | fs.writeFileSync(resultPath, `${resultJson}\n`) 37 | 38 | const version = flutterVersionJson.flutter.version 39 | const channel = flutterVersionJson.flutter.channel 40 | 41 | core.exportVariable('FLUTTER_VERSION', version) 42 | core.exportVariable('FLUTTER_CHANNEL', channel) 43 | } catch (error) { 44 | core.setFailed(`Error in copyFlutterVersion script: ${error.message}`) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /script/createGitTag.js: -------------------------------------------------------------------------------- 1 | module.exports = async ({ core, context, github }) => { 2 | const { OLD_FLUTTER_VERSION, NEW_FLUTTER_VERSION } = process.env 3 | 4 | if (!OLD_FLUTTER_VERSION) { 5 | core.setFailed('Environment variable OLD_FLUTTER_VERSION is required.') 6 | } 7 | 8 | if (!NEW_FLUTTER_VERSION) { 9 | core.setFailed('Environment variable NEW_FLUTTER_VERSION is required.') 10 | } 11 | 12 | if (OLD_FLUTTER_VERSION === NEW_FLUTTER_VERSION) { 13 | return 14 | } 15 | 16 | // Create a git tag using the GitHub API instead of the git client to skip SSH/GPG key setup. 17 | github.rest.git.createRef({ 18 | owner: context.repo.owner, 19 | repo: context.repo.repo, 20 | ref: `refs/tags/${NEW_FLUTTER_VERSION}`, 21 | sha: context.sha, 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /script/docker_build_android.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker build --target android --build-arg flutter_version=3.19.0 --build-arg android_build_tools_version=30.0.3 --build-arg android_platform_versions="28 31 33 34" --build-arg fastlane_version=2.219.0 -t android-test . 4 | -------------------------------------------------------------------------------- /script/docker_linux_entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | analytic_tools_str="Dart, Flutter and Fastlane" 4 | 5 | if [ "$ENABLE_ANALYTICS" = "true" ]; then 6 | echo -e "Received 'ENABLE_ANALYTICS=true'.\nEnabling analytics for $analytic_tools_str." 7 | 8 | dart --enable-analytics 9 | flutter config --analytics 10 | unset FASTLANE_OPT_OUT_USAGE 11 | 12 | # export COCOAPODS_DISABLE_STATS=1 13 | fi 14 | 15 | exec "$@" 16 | -------------------------------------------------------------------------------- /script/docker_windows_entrypoint.ps1: -------------------------------------------------------------------------------- 1 | $analytic_tools_str = "Dart, Flutter and Fastlane" 2 | 3 | if ($env:ENABLE_ANALYTICS -eq "true") { 4 | Write-Output "Received 'ENABLE_ANALYTICS=true'.`nEnabling analytics for $analytic_tools_str." 5 | 6 | dart --enable-analytics 7 | flutter config --analytics 8 | 9 | if (Test-Path env:FASTLANE_OPT_OUT_USAGE) { 10 | Remove-Item env:FASTLANE_OPT_OUT_USAGE 11 | } 12 | } 13 | else { 14 | dart --disable-analytics 15 | flutter --disable-analytics 16 | $env:POWERSHELL_TELEMETRY_OPTOUT = 1 17 | $env:FASTLANE_OPT_OUT_USAGE = "YES" 18 | # TODO: $env:COCOAPODS_DISABLE_STATS = 1 19 | } 20 | 21 | if ($args.length -gt 0) { 22 | Invoke-Expression "$args" 23 | } 24 | else { 25 | powershell 26 | } 27 | -------------------------------------------------------------------------------- /script/latest_android_ndk.sh: -------------------------------------------------------------------------------- 1 | sdkmanager --list | grep 'ndk' | awk '{print $1}' | grep -oP 'ndk;\d+\.\d+\.\d+$' | tail -1 2 | -------------------------------------------------------------------------------- /script/latest_android_sdk_build_tools.sh: -------------------------------------------------------------------------------- 1 | sdkmanager --list | grep 'build-tools' | awk '{print $1}' | grep -oP 'build-tools;\d+\.\d+\.\d+$' | tail -1 2 | -------------------------------------------------------------------------------- /script/latest_android_sdk_command_line_tools.sh: -------------------------------------------------------------------------------- 1 | curl -s https://developer.android.com/studio/ | grep -o 'tools-[0-9]\{14\}' | head -1 | grep -o '[0-9]\{14\}' 2 | 3 | # Get the latest URL of the Android SDK command line tools 4 | command_line_tools_url="$(curl -s https://developer.android.com/studio/ | grep -o 'https://dl.google.com/android/repository/commandlinetools-linux-[0-9]\+_latest.zip')" 5 | 6 | version=$($command_line_tools_url | grep -o '[0-9]\+') 7 | -------------------------------------------------------------------------------- /script/latest_android_sdk_platforms.sh: -------------------------------------------------------------------------------- 1 | sdkmanager --list | grep 'platforms;android' | awk '{print $1}' | grep -oP '\d+$' | sort -n | tail -1 2 | -------------------------------------------------------------------------------- /script/renovate_validate.sh: -------------------------------------------------------------------------------- 1 | npx --yes --package renovate -- renovate-config-validator --strict 2 | -------------------------------------------------------------------------------- /script/setEnvironmentVariables.js: -------------------------------------------------------------------------------- 1 | module.exports = async ({ core }) => { 2 | const { VERSION_MANIFEST, GITHUB_REPOSITORY_OWNER, IMAGE_REPOSITORY_NAME } = 3 | process.env 4 | 5 | if (!VERSION_MANIFEST) { 6 | core.setFailed('Environment variable VERSION_MANIFEST is required.') 7 | return false 8 | } 9 | 10 | if (!GITHUB_REPOSITORY_OWNER) { 11 | core.setFailed('Environment variable GITHUB_REPOSITORY_OWNER is required.') 12 | return false 13 | } 14 | 15 | if (!IMAGE_REPOSITORY_NAME) { 16 | core.setFailed('Environment variable IMAGE_REPOSITORY_NAME is required.') 17 | return false 18 | } 19 | 20 | const fs = require('fs') 21 | const text = fs.readFileSync(VERSION_MANIFEST, 'utf8') 22 | const data = JSON.parse(text) 23 | 24 | const platforms = data.android.platforms 25 | .map((platform) => platform.version) 26 | .join(' ') 27 | 28 | core.exportVariable('FLUTTER_VERSION', data.flutter.version) 29 | core.exportVariable('FASTLANE_VERSION', data.fastlane.version) 30 | core.exportVariable( 31 | 'ANDROID_BUILD_TOOLS_VERSION', 32 | data.android.buildTools.version 33 | ) 34 | core.exportVariable('ANDROID_PLATFORM_VERSIONS', platforms) 35 | core.exportVariable('ANDROID_NDK_VERSION', data.android.ndk.version) 36 | core.exportVariable('CMAKE_VERSION', data.android.cmake.version) 37 | core.exportVariable( 38 | 'IMAGE_REPOSITORY_PATH', 39 | `${GITHUB_REPOSITORY_OWNER}/${IMAGE_REPOSITORY_NAME}` 40 | ) 41 | 42 | return true 43 | } 44 | -------------------------------------------------------------------------------- /script/test.sh: -------------------------------------------------------------------------------- 1 | docker compose build android && container-structure-test test --image docker.io/library/flutter-docker-image-android --config test/android.yml 2 | -------------------------------------------------------------------------------- /script/test_windows.sh: -------------------------------------------------------------------------------- 1 | docker compose build android && container-structure-test-windows-amd64.exe test --image docker.io/library/flutter-docker-image-android --config test\android.yml 2 | -------------------------------------------------------------------------------- /script/updateAndroidVersions.gradle.kts: -------------------------------------------------------------------------------- 1 | // Snippet to include at the end of android/app/build.gradle.kts 2 | 3 | tasks.register("updateAndroidVersions") { 4 | doLast { 5 | val jsonFile = File("../../config/version.json") 6 | 7 | // Parse existing JSON file 8 | val resultJsonMap = groovy.json.JsonSlurper().parseText(jsonFile.readText()) as MutableMap 9 | 10 | // Get unique platform versions 11 | val platformVersions = listOf( 12 | flutter.targetSdkVersion, 13 | flutter.compileSdkVersion 14 | ).distinct() 15 | 16 | // Create new Android version data 17 | val newJsonMap = mapOf( 18 | "platforms" to platformVersions.map { 19 | mapOf("version" to it) 20 | }, 21 | "gradle" to mapOf("version" to gradle.gradleVersion), 22 | "ndk" to mapOf("version" to flutter.ndkVersion) 23 | ) 24 | 25 | // Merge new values into the existing JSON structure 26 | (resultJsonMap["android"] as? MutableMap)?.putAll(newJsonMap) 27 | 28 | // Format JSON with pretty printing 29 | val jsonStr = groovy.json.JsonOutput.toJson(resultJsonMap) 30 | val prettyStr = groovy.json.JsonOutput.prettyPrint(jsonStr) 31 | 32 | println(prettyStr) 33 | 34 | // Write updated JSON back to the file 35 | jsonFile.writeText("$prettyStr\n") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /script/updateFastlaneVersion.js: -------------------------------------------------------------------------------- 1 | module.exports = async ({ core, fetch }) => { 2 | const versionFileUrl = 3 | 'https://rubygems.org/api/v1/versions/fastlane/latest.json' 4 | 5 | let version 6 | try { 7 | const response = await fetch(versionFileUrl) 8 | 9 | const data = await response.json() 10 | 11 | version = data.version 12 | } catch (error) { 13 | console.error( 14 | `An error occurred while requesting the file URL: ${versionFileUrl}`, 15 | error 16 | ) 17 | 18 | return false 19 | } 20 | 21 | if (version === undefined) { 22 | core.setFailed(`Fastlane version URL ${versionFileUrl} doesn't exist`) 23 | 24 | return false 25 | } 26 | 27 | // Update result file, i.e. version.json 28 | const fs = require('fs') 29 | const resultPath = 'config/version.json' 30 | const data = fs.readFileSync(resultPath, 'utf8') 31 | const json = JSON.parse(data) 32 | 33 | const result = { 34 | ...json, 35 | fastlane: { 36 | version, 37 | }, 38 | } 39 | 40 | resultJson = JSON.stringify(result, null, 4) 41 | 42 | fs.writeFileSync(resultPath, `${resultJson}\n`) 43 | } 44 | -------------------------------------------------------------------------------- /script/updateFlutterVersion.js: -------------------------------------------------------------------------------- 1 | module.exports = async ({ core, fetch }) => { 2 | const linuxReleasesUrl = 3 | 'https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json' 4 | const stableReleasePattern = /^\d+\.\d+\.\d+$/g 5 | const resultPath = 'config/flutter_version.json' 6 | 7 | /** 8 | * Downloads the flutter releases from URL 9 | * 10 | * @param {*} fileUrl 11 | * @returns object|boolean 12 | */ 13 | async function downloadReleases(core, fileUrl) { 14 | try { 15 | const response = await fetch(fileUrl) 16 | 17 | return response.json() 18 | } catch (error) { 19 | core.error( 20 | `An error occurred while requesting the file URL ${fileUrl}: ${error}` 21 | ) 22 | 23 | return false 24 | } 25 | } 26 | 27 | const linuxReleasesResponse = await downloadReleases(core, linuxReleasesUrl) 28 | 29 | if (linuxReleasesResponse === false) { 30 | core.setFailed( 31 | `Could not download Flutter version manifest from ${fileUrl}.` 32 | ) 33 | 34 | return false 35 | } 36 | 37 | const { releases } = linuxReleasesResponse 38 | const latestRelease = releases.find((r) => 39 | r.version.match(stableReleasePattern) 40 | ) 41 | 42 | const fs = require('fs') 43 | const data = fs.readFileSync(resultPath, 'utf8') 44 | const oldJson = JSON.parse(data) 45 | 46 | const { version, channel, hash: commit } = latestRelease 47 | 48 | if (oldJson.flutter.version === version) { 49 | core.info(`Flutter version ${version} is already set.`) 50 | 51 | return false 52 | } 53 | 54 | // Update result file, i.e. version.json 55 | const newJson = { 56 | ...oldJson, 57 | flutter: { 58 | channel, 59 | commit, 60 | version, 61 | }, 62 | } 63 | 64 | // Write outputs 65 | resultJson = JSON.stringify(newJson, null, 4) 66 | fs.writeFileSync(resultPath, `${resultJson}\n`) 67 | core.exportVariable('FLUTTER_VERSION', version) 68 | 69 | return true 70 | } 71 | -------------------------------------------------------------------------------- /script/update_changelog.sh: -------------------------------------------------------------------------------- 1 | # TODO: Add image registry URLs to the release changelog 2 | 3 | npx git-cliff -t 3.29.3 -o changelog.md 4 | -------------------------------------------------------------------------------- /script/update_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # TODO: Update all versions used in android.yml from version.json, like NDK, CMake, etc. 4 | 5 | # Path to the JSON and YAML files 6 | version_file_path="./config/version.json" 7 | test_file_path="./test/android.yml" 8 | temp_file_path="./test/temp.yml" 9 | 10 | # Extracting the version value from the version.json file 11 | android_cmdline_tools_version=$(cue eval -e 'android.cmdlineTools.version' "$version_file_path" | tr -d '"') 12 | android_cmdline_tools_test_expected_content="Pkg.Revision=$android_cmdline_tools_version 13 | Pkg.Path=cmdline-tools;$android_cmdline_tools_version 14 | Pkg.Desc=Android SDK Command-line Tools" 15 | 16 | # Check if the version value is not empty 17 | if [ -z "$android_cmdline_tools_version" ]; then 18 | echo "Error: Version not found in $version_file_path" 19 | exit 1 20 | fi 21 | 22 | 23 | # Update the version YAML file using cue 24 | cue export config/android.cue -l input: ./test/android.yml -t android_cmdline_tools_version="$android_cmdline_tools_version" -t android_cmdline_tools_test_expected_content="$android_cmdline_tools_test_expected_content" -e output --out yaml >"$temp_file_path" 25 | mv "$temp_file_path" "$test_file_path" 26 | 27 | # Write progress 28 | echo "Updated $test_file_path with android_cmdline_tools_version: $android_cmdline_tools_version" 29 | -------------------------------------------------------------------------------- /test/android.yml: -------------------------------------------------------------------------------- 1 | schemaVersion: 2.0.0 2 | commandTests: 3 | - name: Gradle, licenses and platforms are already downloaded 4 | setup: 5 | - - flutter 6 | - create 7 | - test_app 8 | teardown: 9 | - - rm 10 | - -r 11 | - test_app 12 | command: bash 13 | args: 14 | - -c 15 | - | 16 | cd test_app/android \ 17 | && timeout --preserve-status 480s ./gradlew bundleRelease 18 | excludedOutput: 19 | - Checking 20 | - Installing 21 | - Downloading 22 | - name: Android SDK build tools is pinned 23 | command: ls 24 | args: 25 | - /home/flutter/sdks/android-sdk/build-tools 26 | expectedOutput: 27 | - 34.0.0 28 | - name: Android NDK is pinned 29 | command: ls 30 | args: 31 | - /home/flutter/sdks/android-sdk/ndk 32 | expectedOutput: 33 | - 26.3.11579264 34 | - name: CMake is pinned 35 | command: ls 36 | args: 37 | - /home/flutter/sdks/android-sdk/cmake 38 | expectedOutput: 39 | - 3.22.1 40 | - name: Android SDK build tools directory only has one directory 41 | command: bash 42 | args: 43 | - -c 44 | - | 45 | ls /home/flutter/sdks/android-sdk/build-tools \ 46 | | wc -l 47 | - name: Fastlane can run lanes 48 | setup: 49 | - - flutter 50 | - create 51 | - test_app 52 | - - mkdir 53 | - -p 54 | - /home/flutter/test_app/android/fastlane 55 | - - touch 56 | - /home/flutter/test_app/android/fastlane/Appfile 57 | - - sh 58 | - -c 59 | - |- 60 | echo 'lane :hello do 61 | puts "Hello" 62 | end' > /home/flutter/test_app/android/fastlane/Fastfile 63 | - - touch 64 | - /home/flutter/test_app/android/fastlane/Pluginfile 65 | teardown: 66 | - - rm 67 | - -r 68 | - test_app 69 | command: bash 70 | args: 71 | - -c 72 | - | 73 | cd test_app/android \ 74 | && timeout --preserve-status 240s fastlane hello 75 | excludedOutput: 76 | - Checking 77 | - Installing 78 | - Downloading 79 | - name: Fastlane usage is opted-out 80 | command: fastlane 81 | args: 82 | - action 83 | - debug 84 | excludedOutput: 85 | - Sending anonymous analytics information 86 | fileContentTests: 87 | - name: Android SDK Command-line Tools is version 19.0 88 | path: /home/flutter/sdks/android-sdk/cmdline-tools/latest/source.properties 89 | expectedContents: 90 | - |- 91 | Pkg.Revision=19.0 92 | Pkg.Path=cmdline-tools;19.0 93 | Pkg.Desc=Android SDK Command-line Tools 94 | - name: Dart and Flutter analytics are disabled 95 | path: /home/flutter/.dart-tool/dart-flutter-telemetry.config 96 | expectedContents: 97 | - reporting=0 98 | -------------------------------------------------------------------------------- /windows.Dockerfile: -------------------------------------------------------------------------------- 1 | # escape=` 2 | 3 | FROM mcr.microsoft.com/windows/servercore:ltsc2025@sha256:c6b2b26058a096cb3f627ed03d0be66bea262c89222c988b516e63ae68f3ea72 as flutter 4 | 5 | SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] 6 | 7 | ARG git_version=2.46.0 8 | ARG git_installation_path="C:\Program Files\Git" 9 | 10 | # TODO: Find a way to pass $env:USERPROFILE instead of hardcoding C:\Users\ContainerUser. It's hardcoded because environment variables in Windows container works by setting for the Machine scope and that will have $env:USERPROFILE as C:\Users\ContainerAdministrator instead. 11 | ENV USERPROFILE="C:\Users\ContainerUser" 12 | ENV SDK_ROOT="${USERPROFILE}\sdks" 13 | ENV FLUTTER_ROOT="${SDK_ROOT}\flutter" 14 | # Set FLUTTER_GIT_URL to fix warning: "Upstream repository unknown source is not a standard remote. Set environment variable "FLUTTER_GIT_URL" to unknown source to dismiss this error." 15 | ENV FLUTTER_GIT_URL="unknown source" 16 | 17 | WORKDIR "$USERPROFILE" 18 | 19 | # Install Git because is required by Flutter 20 | RUN $installer = \"MinGit-${env:git_version}-busybox-64-bit.zip\"; ` 21 | $url = \"https://github.com/git-for-windows/git/releases/download/v${env:git_version}.windows.1/${installer}\"; ` 22 | Invoke-WebRequest -Uri "$url" -OutFile "$installer"; ` 23 | Expand-Archive -Path "$installer" -DestinationPath "$env:git_installation_path"; ` 24 | Remove-Item -Path "$installer"; 25 | 26 | # The user ContainerAdministrator must be used because is the one that has permissions to set the system PATH 27 | USER ContainerAdministrator 28 | 29 | # The PATH variable will be updated in the next shell session, so the RUN command that sets the PATH needs to be separated from the one that uses it 30 | RUN [Environment]::SetEnvironmentVariable('PATH', \"${env:PATH};${env:git_installation_path}\cmd;${env:git_installation_path}\usr\bin;${env:FLUTTER_ROOT}\bin;${env:FLUTTER_ROOT}\bin\cache\dart-sdk\bin;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\msbuild\current\bin\", 'Machine'); 31 | 32 | # MinGit has a circular reference in its global configuration, which causes git to crash 33 | # See https://github.com/git-for-windows/git/issues/2387#issuecomment-679367609 34 | # hadolint ignore=DL3059 35 | RUN $env:GIT_CONFIG_NOSYSTEM=1; git config --system --unset-all include.path; 36 | 37 | # Switch to the non-admin user when the admin user is not needed anymore 38 | USER ContainerUser 39 | 40 | ARG flutter_version 41 | 42 | RUN git clone ` 43 | --depth 1 ` 44 | --branch "$env:flutter_version" ` 45 | https://github.com/flutter/flutter ` 46 | "$env:FLUTTER_ROOT"; ` 47 | # To fix fatal: detected dubious ownership in repository at 'C:/Users/ContainerUser/sdks/flutter/.git' owned by BUILTIN/Administrators but the current user is: User Manager/ContainerUser 48 | git config --global --add safe.directory "$env:FLUTTER_ROOT"; ` 49 | flutter --version; ` 50 | dart --disable-analytics; ` 51 | flutter config ` 52 | --no-cli-animations ` 53 | --no-analytics ` 54 | --no-enable-android ` 55 | --no-enable-web ` 56 | --no-enable-linux-desktop ` 57 | --enable-windows-desktop ` 58 | --no-enable-fuchsia ` 59 | --no-enable-custom-devices ` 60 | --no-enable-ios ` 61 | --no-enable-macos-desktop; ` 62 | flutter doctor --verbose; ` 63 | flutter precache --windows; ` 64 | flutter create build_app; 65 | 66 | 67 | # The user ContainerAdministrator must be used because is the one that has permissions to install with vs_BuildTools 68 | USER ContainerAdministrator 69 | # Download the Build Tools bootstrapper 70 | # See https://learn.microsoft.com/en-us/visualstudio/install/build-tools-container?view=vs-2022 71 | RUN Invoke-WebRequest -Uri https://aka.ms/vs/17/release/vs_buildtools.exe -OutFile vs_BuildTools.exe; ` 72 | Start-Process vs_BuildTools.exe -ArgumentList '--quiet --wait --norestart --nocache ` 73 | --add Microsoft.VisualStudio.Component.VC.CMake.Project ` 74 | --add Microsoft.VisualStudio.Component.Windows11SDK.22621 ` 75 | --add Microsoft.VisualStudio.Workload.VCTools' ` 76 | -Wait; ` 77 | Remove-Item vs_BuildTools.exe; 78 | USER ContainerUser 79 | 80 | WORKDIR "$USERPROFILE/build_app" 81 | RUN flutter build windows; 82 | 83 | WORKDIR "$USERPROFILE" 84 | COPY ./script/docker_windows_entrypoint.ps1 "docker_entrypoint.ps1" 85 | 86 | ENTRYPOINT "C:\Users\ContainerUser\docker_entrypoint.ps1" 87 | 88 | RUN Remove-Item -Recurse build_app; 89 | -------------------------------------------------------------------------------- /windows.md: -------------------------------------------------------------------------------- 1 | # Windows 2 | 3 | ## Swich between Linux and Windows containers 4 | 5 | & $Env:ProgramFiles\Docker\Docker\DockerCli.exe -SwitchDaemon 6 | 7 | ## TODO 8 | 9 | 1. Install tools 10 | 11 | ```powershell` 12 | # # needed? No 13 | # --add Microsoft.Component.MSBuild' ` 14 | # # needed? No 15 | # --add Microsoft.VisualStudio.Component.TestTools.BuildTools ` 16 | # # needed? No 17 | # --add Microsoft.VisualStudio.Component.VC.ASAN ` 18 | # # needed? no 19 | # # --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` 20 | RUN Invoke-WebRequest -Uri https://aka.ms/vs/17/release/vs_buildtools.exe -OutFile vs_BuildTools.exe; ` 21 | Start-Process vs_BuildTools.exe -ArgumentList '--quiet --wait --norestart --nocache ` 22 | # # needed? yes 23 | # --add Microsoft.VisualStudio.Component.VC.CMake.Project ` 24 | # # needed? Yes 25 | # --add Microsoft.VisualStudio.Component.Windows11SDK.22621 ` 26 | # # needed? 27 | # --add Microsoft.VisualStudio.Workload.VCTools' ` 28 | -Wait; ` 29 | Remove-Item vs_BuildTools.exe; 30 | ``` 31 | 32 | 1. Check how it can be run in Github actions. 33 | 1. Check how it can be run in Gitlab CI/CD. 34 | 1. Test where is installed. 35 | 1. Test that path to powershell.exe exists. 36 | 1. Test with a snapshot of flutter config to determine if new feature flags should be enabled or disabled. 37 | 1. Test that Build Tools were installed in C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\msbuild\current\bin 38 | 1. Check [Windows installation requirements for Flutter](https://docs.flutter.dev/get-started/install/windows/desktop) 39 | 1. Add docs explaining to use `$VerbosePreference = 'Continue';` in the SHELL to debug unexpected pwsh problems. 40 | 41 | ## Open issue in windows Docker images repo 42 | 43 | 1. Some images can be pulled while others give error: 44 | 45 | ```text 46 | Error response from daemon: Get "https://mcr.microsoft.com/v2/": read tcp [2a0c:5a84:e100:e501::a97c]:58039->[2603:1061:f:101::10]:443: wsarecv: An existing connection was forcibly closed by the remote host. 47 | ``` 48 | 49 | Debug with `curl -A github165 -v https://mcr.microsoft.com/v2/powershell/manifests/lts-nanoserver-ltsc2022` 50 | 51 | ## Contribute flutter upstream 52 | 53 | 1. Remove `WHERE` in bin\internal\shared.bat and use instead: 54 | 55 | ```batch 56 | pwsh.exe -Command "exit" >nul 2>&1 && ( 57 | SET powershell_executable=pwsh.exe 58 | ) || powershell.exe -Command "exit" >nul 2>&1 && ( 59 | SET powershell_executable=PowerShell.exe 60 | ) || ( 61 | ECHO Error: PowerShell executable not found. 1>&2 62 | ECHO Either pwsh.exe or PowerShell.exe must be in your PATH. 1>&2 63 | EXIT 1 64 | ) 65 | ``` 66 | 67 | 1. Find if the executable should be pwsh or powershell and put it in a service to remove the hardcoded "powershell" in multiple places, like in: 68 | 69 | - dev\devicelab\lib\framework\running_processes.dart 70 | - packages\flutter_tools\lib\src\windows\windows_version_validator.dart 71 | 72 | ## Steps to reproduce in Docker 73 | 74 | 1. Enable Windows Developer Settings to solve error: 75 | 76 | >Building with plugins requires symlink support. 77 | > 78 | >Please enable Developer Mode in your system settings. Run 79 | > start ms-settings:developers 80 | >to open settings. 81 | 82 | ```powershell 83 | reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1" 84 | ``` 85 | 86 | 1. For CI/CD 87 | 88 | 1. Docker version must be pinned in Github workflow to avoid breaking changes: with escaping `\"` syntax inside RUN directive, etc. 89 | 90 | 1. Packaging tool in Windows: . It uses the executables: 91 | 92 | - [makeappx.exe](https://learn.microsoft.com/en-us/windows/win32/appxpkg/make-appx-package--makeappx-exe-) 93 | - [makepri.exe](https://learn.microsoft.com/en-us/windows/uwp/app-resources/makepri-exe-command-options) 94 | - [signtool.exe](https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe) 95 | 96 | - certificate 97 | - Make a note that --install-certificate should be "false" or configured because the certificate can't be installed as ContainerUser. 98 | 99 | ```powershell 100 | # OK 101 | Import-PfxCertificate -FilePath "C:\Users\ContainerUser\AppData\Local\Pub\Cache\hosted\pub.dev\msix-3.16.8\lib\assets\test_certificate.pfx" -Password (ConvertTo-SecureString -AsPlainText -Force "1234") -CertStoreLocation Cert:\LocalMachine\Root 102 | 103 | # Doesn't work 104 | Import-PfxCertificate -FilePath "C:\Users\ContainerUser\AppData\Local\Pub\Cache\hosted\pub.dev\msix-3.16.8\lib\assets\test_certificate.pfx" -Password (ConvertTo-SecureString -AsPlainText -Force "1234") 105 | ``` 106 | 107 | 1. Install msstore CLI https://github.com/microsoft/msstore-cli It seems behind StoreBroker but it looks that it's going to be the primary and recommended way to publish to Microsoft Store 108 | 109 | - According to the [msstore guide](https://learn.microsoft.com/en-us/windows/apps/publish/msstore-dev-cli/commands?pivots=msstoredevcli-installer-linux#installation), It will be needed to install Microsoft.NetCore.Component.Runtime.8.0 with vs_BuildTools 110 | 111 | 1. From => install This is currently the primary tool to publish to Microsoft Store 112 | 113 | - Not installed right now 114 | 115 | 1. Install the [Windows App Certification Kit](https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/windows-app-certification-kit) or the [Windows SDK that already includes it](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) 116 | 117 | - Installed currently by one of the workloads in vs_BuildTools 118 | 119 | ## References 120 | 121 | - [How environment variables work on Windows containers?](https://blog.sixeyed.com/windows-weekly-dockerfile-14-environment-variables/) 122 | - [Windows deployment in Flutter](https://docs.flutter.dev/deployment/windows) 123 | - [vs_BuildTools workloads](https://learn.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2022&preserve-view=true) 124 | - Useful Dockerfile https://git.openprivacy.ca/openprivacy/flutter-desktop/src/branch/main/windows/Dockerfile 125 | --------------------------------------------------------------------------------