Setting up a .gitlab-ci.yml
file in the root directory enables GitLab to automatically detect and execute CI/CD pipelines. This guide walks through the setup, including best practices for defining runners, handling sensitive data, selecting the correct Docker image, and ensuring a streamlined build process.
Before configuring the CI/CD pipeline, you need to ensure that a GitLab Runner is available. If a runner is not yet set up, ask the SRE (Site Reliability Engineering) team for assistance in registering a runner.
To verify a runner is available:
1. Go to GitLab Project → Settings → CI/CD → Runners.
2. Ensure at least one runner is active and assigned to your project.
If a runner is missing, request SRE support to register one.
Never store sensitive information in the GitLab CI/CD YAML file. Instead, use GitLab CI/CD variables:
- Navigate to GitLab Project → Settings → CI/CD → Variables.
- Add the required secret values (e.g., keystore files, API keys).
- Use the following method to decode Base64-encoded files:
echo $YOUR_GITLAB_CI_VARIABLE | base64 -di > your-file-name.extension
- Example: Decoding a Keystore file:
echo $KEYSTORE_FILE | base64 -di > mykeystore.jks
If needed, use this tool to encode files into Base64 format: File to Base64 Tool.
Ensure that the Docker image used in GitLab CI/CD matches the local development environment. You can find official images on Docker Hub or use an internally cloned image for faster builds.
Example:
image: ghcr.io/cirruslabs/flutter:3.27.1
Consider cloning the image to your private server to reduce external dependencies.
- Use
rules
Instead ofonly
orexcept
(deprecated in GitLab 13.2+). - Use
tags:
to ensure the pipeline is executed by an appropriate runner. - Avoid Multi-line Commands: GitLab CI/CD does not support multi-line scripts. Use
;
to separate commands.
Example of an optimized script:
script:
- apt-get update && apt-get install -y curl gnupg; \
curl -fsSL https://deb.nodesource.com/setup_18.x | bash -; \
apt-get install -y nodejs; \
npm install -g firebase-tools; \
firebase --version
Use Git tags to generate build versions dynamically. The tag format follows:
[project-type]-[build-type]-[version]-[file-type]
Examples:
gen-integ-10020304-apk
→ Version1.2.3.4-integ
, builds an APK.gen-prod-100203-aab
→ Version1.2.3
, builds an AAB.
The build script extracts version details using shell commands:
script:
- BUILD_TYPE=$(echo $CI_COMMIT_TAG | cut -d '-' -f 2)
- BUILD_NUMBER=$(echo $CI_COMMIT_TAG | cut -d '-' -f 3)
- FILE_TYPE=$(echo $CI_COMMIT_TAG | cut -d '-' -f 4)
image : ghcr.io/cirruslabs/flutter:3.27.1
stages:
- buildvariables:
APK_OUTPUT_DIR: "build/app/outputs/flutter-apk"
AAB_OUTPUT_DIR: "build/app/outputs/bundle/release"
FIREBASE_APP_ID: ""
APP_ALIAS: ""
BUILD_NAME: ""
BUILD_NUMBER: ""
FILE_TYPE: ""before_script:
- cd android
- echo $KEYSTORE_FILE | base64 -di > mykeystore.jks
- echo $KEY_PROPERTIES | base64 -di > key.properties
- cd ..
- flutter --version
- flutter pub get
- apt-get update && apt-get install -y curl gnupg
- curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
- apt-get install -y nodejs
- npm install -g firebase-tools
- firebase --versionbuild:
stage: build
script:
- echo "Parsing tag $CI_COMMIT_TAG...";
- BUILD_TYPE=$(echo $CI_COMMIT_TAG | cut -d '-' -f 2);
- BUILD_NUMBER=$(echo $CI_COMMIT_TAG | cut -d '-' -f 3);
- FILE_TYPE=$(echo $CI_COMMIT_TAG | cut -d '-' -f 4);
- if [[ "$BUILD_TYPE" == "prod" && ${#BUILD_NUMBER} -ne 6 ]]; then echo "Invalid build number for prod"; exit 1; fi;
- if [[ "$BUILD_TYPE" != "prod" && ${#BUILD_NUMBER} -ne 8 ]]; then echo "Invalid build number for integ/sbx"; exit 1; fi;
- flutter build $FILE_TYPE --release --build-name=$BUILD_NAME --build-number=$BUILD_NUMBER;
- if [[ "$FILE_TYPE" == "apk" ]]; then firebase appdistribution:distribute $APK_OUTPUT_DIR/app-release.apk --app $FIREBASE_APP_ID --token $FIREBASE_TOKEN --groups testers; fi;
artifacts:
paths:
- $APK_OUTPUT_DIR/app-release.apk
- $AAB_OUTPUT_DIR/app-release.aab
expire_in: 1 week
rules:
- if: '$CI_COMMIT_TAG =~ /.*-apk|.*-aab/'
tags:
- build
This guide outlines best practices for setting up a GitLab CI/CD pipeline, securely managing sensitive data, and optimizing build scripts. By following these steps, your project will have a consistent, efficient, and automated deployment process.