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
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
stages:
- build
- test
- deploy
variables:
# https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast
GITLAB_ADVANCED_SAST_ENABLED: 'true'
# https://docs.gitlab.com/user/application_security/sast/#vulnerability-filters
# https://stackoverflow.com/a/71111784
SAST_EXCLUDED_PATHS: 'spec,test,test-d,test-federation,test-server,tests,tmp,cypress,coverage,node_modules,build,built,built-js,*.min.js,megalodon/lib,libopenmpt'
DS_EXCLUDED_PATHS: 'spec,test,test-d,test-federation,test-server,tests,tmp,cypress,coverage,node_modules,build,built,built-js,*.min.js,megalodon/lib,libopenmpt,packages/*/src' # save time: skip source directories
# https://docs.gitlab.com/user/application_security/dependency_scanning/migration_guide_to_sbom_based_scans/
DS_ENFORCE_NEW_ANALYZER: 'true'
DS_MAX_DEPTH: -1
# https://docs.gitlab.com/user/application_security/dependency_scanning/static_reachability/
DS_STATIC_REACHABILITY_ENABLED: true
# https://docs.gitlab.com/user/application_security/detect/security_configuration/#use-security-scanning-tools-with-merge-request-pipelines
AST_ENABLE_MR_PIPELINES: 'true'
.common: &common
# "only" has been removed, so we use rules.
# This runs in MR pipelines *or* push to develop/stable
rules: &common-rules
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_PIPELINE_SOURCE == 'push' && ($CI_COMMIT_BRANCH == 'develop' || $CI_COMMIT_BRANCH == 'stable')
.deploy_common: &deploy_common
stage: deploy
# Only run when pushing to stable, develop, or tags
rules: &deploy-rules
- if: $CI_PIPELINE_SOURCE != 'push'
when: never
- if: $CI_COMMIT_BRANCH == 'develop'
- if: $CI_COMMIT_BRANCH == 'stable'
- if: $CI_COMMIT_TAG
# https://docs.gitlab.com/user/application_security/sast/
include:
- local: '.gitlab/ci_templates/dependency_scanning.yml'
rules: *common-rules
- local: '.gitlab/ci_templates/container_scanning.yml'
rules: *deploy-rules
- local: '.gitlab/ci_templates/sast.yml'
rules: *common-rules
- local: '.gitlab/ci_templates/secret_detection.yml'
rules: *common-rules
- local: '.gitlab/ci_templates/lib_behave.yml'
rules: *common-rules
# Cache node_modules and share build artifacts for the pipeline.
# This shares the same cache definition, but it's the only place that actually *pushes* to the cache.
# https://docs.gitlab.com/ci/caching/
# https://github.com/pnpm/pnpm/issues/1174#issuecomment-996719439
# https://github.com/pnpm/pnpm/issues/1174#issuecomment-1641267133
build: &build
<<: *common
stage: build
image:
name: docker.io/node:22
pull_policy: if-not-present
variables:
POSTGRES_PASSWORD: 'ci'
COREPACK_DEFAULT_TO_LATEST: '0'
# Arm64 is recommended for CI
tags:
- arm64
before_script:
- apt-get update && apt-get install -y git wget curl build-essential python3 ffmpeg libcairo2-dev libpango1.0-dev libpangocairo-1.0
- 'echo "clusterLimit: $(nproc)" >> .config/ci.yml'
- cp .config/ci.yml .config/default.yml
- cp .config/ci.yml .config/test.yml
- corepack enable
- corepack install
- git submodule update --init
- pnpm config set store-dir .pnpm-store
- pnpm install --frozen-lockfile
script:
- pnpm run build
cache:
- &cache-pnpm
key:
files:
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
paths:
- '.pnpm-store/'
- 'node_modules/'
- 'packages/*/node_modules/'
- 'packages/misskey-js/generator/node_modules/'
policy: pull-push
when: on_success
- &cache-build
key: "$CI_COMMIT_REF_SLUG"
paths:
- 'built/'
- 'packages/*/built/'
- 'packages/megalodon/lib/'
policy: pull-push
when: on_success
.test_common: &test_common
<<: *common
<<: *build
stage: test
cache:
-
<<: *cache-pnpm
policy: pull
-
<<: *cache-build
policy: pull
lint:
<<: *test_common
script:
- pnpm run build-assets
- pnpm run eslint
backend_tests:
<<: *test_common
services:
- name: postgres:15
pull_policy: if-not-present
- name: redis
pull_policy: if-not-present
script:
- pnpm run --filter backend build:pre
- pnpm run --filter backend build
- pnpm run --filter backend migrate
- pnpm run --filter backend test
# Same as common, but MRs are only run if they modify the backend.
rules:
- if: $CI_PIPELINE_SOURCE == 'push' && ($CI_COMMIT_BRANCH == 'develop' || $CI_COMMIT_BRANCH == 'stable')
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes:
- 'packages/backend/**/*'
- 'packages/megalodon/**/*'
- 'packages/misskey-js/**/*'
- 'packages/*' # single-star is intention - we don't want to recurse!
- 'scripts/**/*'
- 'eslint/**/*'
- 'chart/**/*'
- '.config/**/*'
frontend_tests:
<<: *test_common
script:
- pnpm run --filter frontend build:pre
- pnpm run --filter frontend build
- pnpm run --filter frontend test
# Same as common, but MRs are only run if they modify the frontend.
rules:
- if: $CI_PIPELINE_SOURCE == 'push' && ($CI_COMMIT_BRANCH == 'develop' || $CI_COMMIT_BRANCH == 'stable')
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes:
- 'packages/frontend/**/*'
- 'packages/frontend-embed/**/*'
- 'packages/frontend-shared/**/*'
- 'packages/misskey-js/**/*'
- 'packages/misskey-bubble-game/**/*'
- 'packages/misskey-reversi/**/*'
- 'packages/sw/**/*'
- 'packages/*' # single-star is intention - we don't want to recurse!
- 'scripts/**/*'
- 'eslint/**/*'
- 'locales/**/*'
- 'sharkey-locales/**/*'
- 'cypress/**/*'
- 'assets/**/*'
misskey-js_tests:
<<: *test_common
script:
- pnpm run --filter misskey-js build
- pnpm run --filter misskey-js test
megalodon_tests:
<<: *test_common
script:
- pnpm run --filter megalodon build
- pnpm run --filter megalodon test
get_image_tag:
<<: *deploy_common
image:
name: docker.io/alpine:latest
pull_policy: if-not-present
script:
- apk add jq
- |
if test -n "$CI_COMMIT_TAG"; then
tag="$CI_COMMIT_TAG"
elif test "$CI_COMMIT_BRANCH" == "stable"; then
tag="latest"
elif test "$CI_COMMIT_BRANCH" == "develop"; then
tag="develop"
else
tag="$CI_COMMIT_BRANCH"
fi
version=$(cat package.json | jq -r '.version')
- echo "REGISTRY_PUSH_TAG=$tag" >> build.env
- echo "REGISTRY_PUSH_VERSION=$version" >> build.env
artifacts:
reports:
dotenv: build.env
build_image:
<<: *deploy_common
needs:
- job: get_image_tag
artifacts: true
parallel:
matrix:
- ARCH: amd64
- ARCH: arm64
tags:
- ${ARCH}
image:
name: gcr.io/kaniko-project/executor:debug
pull_policy: if-not-present
entrypoint: [""]
script:
- >-
/kaniko/executor \
--context "${CI_PROJECT_DIR}" \
--dockerfile "${CI_PROJECT_DIR}/Dockerfile" \
--single-snapshot \
--destination "${CI_REGISTRY_IMAGE}:${REGISTRY_PUSH_VERSION}-${ARCH}"
merge_image_manifests:
<<: *deploy_common
needs:
- job: build_image
artifacts: false
- job: get_image_tag
artifacts: true
image:
name: mplatform/manifest-tool:alpine
pull_policy: if-not-present
entrypoint: [""]
script:
- >-
manifest-tool \
--username=${CI_REGISTRY_USER} \
--password=${CI_REGISTRY_PASSWORD} \
push from-args \
--platforms linux/amd64,linux/arm64 \
--tags ${REGISTRY_PUSH_VERSION} \
--template ${CI_REGISTRY_IMAGE}:${REGISTRY_PUSH_VERSION}-ARCH \
--target ${CI_REGISTRY_IMAGE}:${REGISTRY_PUSH_TAG}
|