GitLab CI
GitLab CI pipeline configurations for releasing Android apps with GPC. Store your service account JSON in GitLab CI/CD variables as GPC_SERVICE_ACCOUNT (type: Variable, masked, protected).
Basic Release Job
Single job that uploads an AAB to the internal track on tag push.
yaml
# .gitlab-ci.yml
stages:
- build
- release
variables:
GPC_APP: com.example.myapp
build:
stage: build
image: eclipse-temurin:17-jdk
script:
- ./gradlew bundleRelease
artifacts:
paths:
- app/build/outputs/bundle/release/app-release.aab
expire_in: 1 day
only:
- tags
release:
stage: release
image: node:20
variables:
GPC_SERVICE_ACCOUNT: $GPC_SERVICE_ACCOUNT
before_script:
- npm install -g @gpc-cli/cli
script:
- gpc preflight app/build/outputs/bundle/release/app-release.aab --fail-on error --json
- |
gpc releases upload \
app/build/outputs/bundle/release/app-release.aab \
--track internal \
--notes "GitLab CI build ${CI_COMMIT_TAG}" \
--json
only:
- tags
dependencies:
- build1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Multi-Stage Pipeline
Full pipeline with build, upload, promotion, and vitals monitoring stages. Uses GitLab environments for deployment tracking.
yaml
# .gitlab-ci.yml
stages:
- build
- upload
- promote
- monitor
variables:
GPC_APP: com.example.myapp
GPC_SERVICE_ACCOUNT: $GPC_SERVICE_ACCOUNT
CRASH_THRESHOLD: "2.0"
ANR_THRESHOLD: "0.5"
.gpc_setup: &gpc_setup
image: node:20
before_script:
- npm install -g @gpc-cli/cli
# -- Build --
build:
stage: build
image: eclipse-temurin:17-jdk
script:
- ./gradlew bundleRelease
artifacts:
paths:
- app/build/outputs/bundle/release/app-release.aab
expire_in: 7 days
only:
- tags
# -- Upload to Internal --
upload:internal:
stage: upload
<<: *gpc_setup
script:
- |
gpc releases upload \
app/build/outputs/bundle/release/app-release.aab \
--track internal \
--notes "Build ${CI_COMMIT_TAG} (pipeline ${CI_PIPELINE_ID})" \
--json | tee upload-result.json
artifacts:
paths:
- upload-result.json
expire_in: 7 days
environment:
name: internal
dependencies:
- build
only:
- tags
# -- Promote to Beta --
promote:beta:
stage: promote
<<: *gpc_setup
script:
- gpc releases promote --from internal --to beta --json
environment:
name: beta
dependencies:
- upload:internal
only:
- tags
when: manual
# -- Promote to Production (staged) --
promote:production:
stage: promote
<<: *gpc_setup
script:
- gpc releases promote --from beta --to production --rollout 10 --json
environment:
name: production
dependencies:
- promote:beta
only:
- tags
when: manual
# -- Vitals Monitoring --
monitor:vitals:
stage: monitor
<<: *gpc_setup
script:
- |
CRASH_RATE=$(gpc vitals crashes --json | jq -r '.data.crashRate')
ANR_RATE=$(gpc vitals anr --json | jq -r '.data.anrRate')
echo "Crash rate: ${CRASH_RATE}%"
echo "ANR rate: ${ANR_RATE}%"
if (( $(echo "$CRASH_RATE > $CRASH_THRESHOLD" | bc -l) )); then
echo "Crash rate ${CRASH_RATE}% exceeds threshold ${CRASH_THRESHOLD}%"
gpc releases rollout halt --track production --json
exit 1
fi
if (( $(echo "$ANR_RATE > $ANR_THRESHOLD" | bc -l) )); then
echo "ANR rate ${ANR_RATE}% exceeds threshold ${ANR_THRESHOLD}%"
gpc releases rollout halt --track production --json
exit 1
fi
echo "Vitals healthy"
only:
- schedules1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
Metadata Sync
Sync store listing metadata from the repository to Play Console. Validate on merge request, push on merge to main.
yaml
# .gitlab-ci.yml (add to existing pipeline or standalone)
stages:
- validate
- sync
variables:
GPC_APP: com.example.myapp
GPC_SERVICE_ACCOUNT: $GPC_SERVICE_ACCOUNT
validate:metadata:
stage: validate
image: node:20
before_script:
- npm install -g @gpc-cli/cli
script:
- gpc listings push --dir metadata/ --dry-run --json
only:
- merge_requests
changes:
- metadata/**/*
sync:metadata:
stage: sync
image: node:20
before_script:
- npm install -g @gpc-cli/cli
script:
- gpc listings push --dir metadata/ --json
only:
- main
changes:
- metadata/**/*1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Using GitLab CI/CD Variables
Setting Up Secrets
- Navigate to Settings > CI/CD > Variables
- Add
GPC_SERVICE_ACCOUNTwith:- Type: Variable
- Protected: Yes (only available on protected branches/tags)
- Masked: Yes (hidden in job logs)
- Value: The full JSON content of your service account key
Per-Environment Variables
Use GitLab environments to scope service accounts:
yaml
promote:production:
environment:
name: production
variables:
# Uses a production-specific service account
GPC_SERVICE_ACCOUNT: $GPC_PROD_SERVICE_ACCOUNT1
2
3
4
5
6
2
3
4
5
6
Scheduled Pipelines
Create a scheduled pipeline for vitals monitoring:
- Navigate to Build > Pipeline schedules
- Set the cron interval (e.g.,
0 */6 * * *for every 6 hours) - Target the
mainbranch - Add
SCHEDULE_TYPE=vitalsas a pipeline variable
yaml
monitor:vitals:
stage: monitor
<<: *gpc_setup
script:
- gpc vitals overview --json
only:
- schedules
variables:
SCHEDULE_TYPE: vitals1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
