12
Build, Test, dan Rilis
Rilis ua-parser-js berjalan lewat tiga script di script/ dan tiga workflow di .github/workflows/. Semua perintah masuk lewat npm run, sehingga CI tidak perlu menulis ulang langkahnya. package.json:244-2561
| Script | Perintah |
|---|---|
build | ./script/build-esm.js && ./script/build-dist.sh |
build+test | npm run build && npm run test |
test | ./script/test-all.sh |
test:jshint | jshint src/main |
test:eslint | eslint --no-config-lookup src |
test:mocha | mocha --recursive test/unit |
test:playwright | playwright test test/e2e --browser all |
test:lockfile-lint | lockfile-lint -p package-lock.json |
test:dts-lint | tsd --typings src/main/ua-parser.d.ts --files test/static/dts-lint.ts |
test:fuzz | jazzer ./test/fuzz/redos.js --sync |
test:nyc | nyc --timeout=50000 --include=src/**/*.js npm run test |
Build: build-esm.js lalu build-dist.sh
npm run build merangkai dua tahap dengan &&. Tahap pertama menghasilkan versi ESM dan deklarasi tipe. Tahap kedua memampatkan hasilnya menjadi berkas di dist/.
graph LR
SRC["src/main/ua-parser.js<br/>+ 5 modul src lain"] --> ESM["script/build-esm.js"]
ESM --> MJS["*.mjs hasil generate<br/>+ ua-parser-enums.d.ts"]
MJS --> DIST["script/build-dist.sh"]
SRC --> DIST
DIST --> ART["dist/ua-parser.min.js<br/>dist/ua-parser.pack.js<br/>dist/ua-parser.min.mjs<br/>dist/ua-parser.pack.mjs"]
style ESM fill:#f59e0b,color:#000
style DIST fill:#f59e0b,color:#000
style MJS fill:#8b5cf6,color:#fff
style ART fill:#2d7d46,color:#fff
%% fig: Aliran dua tahap npm run build
%% desc: build-esm.js menghasilkan berkas .mjs dan .d.ts, lalu build-dist.sh memampatkan src dan .mjs menjadi empat berkas dist.build-esm.js memakai satu fungsi generateFile untuk setiap entri: berkas src dibaca, daftar replacements dijalankan, lalu hasilnya ditulis ke dest dengan header // DO NOT EDIT THIS FILE! dan komentar // Source: /${src}. script/build-esm.js:14-302
Daftar files berisi delapan entri. Enam di antaranya menghasilkan pasangan .js ke .mjs untuk modul utama, bot-detection, browser-detection, device-detection, extensions, dan helpers. Dua entri membaca src/enums/ua-parser-enums.js. script/build-esm.js:32-913
| Berkas sumber | Berkas hasil |
|---|---|
src/main/ua-parser.js | src/main/ua-parser.mjs |
src/bot-detection/bot-detection.js | src/bot-detection/bot-detection.mjs |
src/browser-detection/browser-detection.js | src/browser-detection/browser-detection.mjs |
src/device-detection/device-detection.js | src/device-detection/device-detection.mjs |
src/enums/ua-parser-enums.js | src/enums/ua-parser-enums.mjs |
src/enums/ua-parser-enums.js | src/enums/ua-parser-enums.d.ts |
src/extensions/ua-parser-extensions.js | src/extensions/ua-parser-extensions.mjs |
src/helpers/ua-parser-helpers.js | src/helpers/ua-parser-helpers.mjs |
Entri enums dipakai dua kali, sekali untuk .mjs dan sekali untuk .d.ts. Penggantian untuk berkas deklarasi mengubah object.freeze menjadi Readonly<, menambah typeof, mengganti }); menjadi }>;, lalu membuang baris module.exports. script/build-esm.js:68-784
Seluruh entri diproses berurutan pada satu baris terakhir: files.forEach(module => generateFile(module)). script/build-esm.js:935
build-dist.sh menetapkan empat pasangan path: src/main/ua-parser.js ke dist/ua-parser.min.js dan dist/ua-parser.pack.js, serta src/main/ua-parser.mjs ke dist/ua-parser.min.mjs dan dist/ua-parser.pack.mjs. script/build-dist.sh:3-96
Empat panggilan uglifyjs mengisi keempat berkas itu. Varian min hanya mempertahankan komentar yang cocok dengan /^ UA/. Varian pack menambahkan --compress --mangle, dan berkas .mjs memakai flag tambahan --module. script/build-dist.sh:11-237
⚠️ Tahap kedua membaca
src/main/ua-parser.mjs, yaitu berkas hasil tahap pertama. Karena itu kedua script dirangkai dengan&&di scriptbuild. Jikabuild-dist.shdijalankan sendiri setelah perubahan padasrc/main/ua-parser.js, yang dipampatkan adalah versi.mjsyang usang. package.json:244-2561
Perkakas kedua tahap adalah devDependencies: uglify-js untuk uglifyjs, ditambah jshint, eslint, mocha, @playwright/test, lockfile-lint, tsd, nyc, dan @jazzer.js/core untuk test. package.json:262-2768
Rantai test-all.sh
npm run test hanya memanggil script/test-all.sh. Script itu menjalankan npm run build lebih dulu, lalu enam langkah lain. Setiap langkah diakhiri || exit 1, sehingga kegagalan pertama menghentikan rangkaian. script/test-all.sh:3-69
graph LR
B["npm run build"] --> J["test:jshint"]
J --> E["test:eslint"]
E --> M["test:mocha"]
M --> P["test:playwright"]
P --> L["test:lockfile-lint"]
L --> D["test:dts-lint"]
B -. "exit 1" .-> FAIL["rangkaian berhenti"]
style B fill:#f59e0b,color:#000
style D fill:#2d7d46,color:#fff
style FAIL fill:#dc2626,color:#fff
%% fig: Urutan gerbang di script test-all.sh
%% desc: build jalan lebih dulu, lalu tujuh langkah lint dan test berurutan; kegagalan satu langkah menghentikan seluruh rangkaian.| Urutan | Langkah | Perintah | Cakupan |
|---|---|---|---|
| 1 | build | npm run build | src/ lalu dist/ |
| 2 | lint js | npm run test:jshint | src/main |
| 3 | lint js | npm run test:eslint | src |
| 4 | unit test | npm run test:mocha | test/unit rekursif |
| 5 | e2e | npm run test:playwright | test/e2e, semua browser |
| 6 | lint lockfile | npm run test:lockfile-lint | package-lock.json |
| 7 | lint tipe | npm run test:dts-lint | src/main/ua-parser.d.ts dan test/static/dts-lint.ts |
Tiga langkah pertama mencakup build, jshint untuk src/main, dan eslint untuk seluruh src. Langkah keempat menjalankan unit test lewat mocha. script/test-all.sh:8-1710
Tiga langkah terakhir menjalankan playwright test test/e2e --browser all, lockfile-lint -p package-lock.json, dan tsd terhadap deklarasi tipe utama. script/test-all.sh:19-3211
test-all.sh tidak memanggil test:fuzz maupun test:nyc. Keduanya harus dijalankan manual bila dibutuhkan untuk uji ReDoS atau pengukuran coverage. package.json:244-2561
CI: Build & Test
Workflow CI: Build & Test berjalan pada setiap push dan pull_request dengan permission contents: read. Job run-test memakai ubuntu-latest dan timeout-minutes: 30. .github/workflows/ci-build-test.yml:9-1912
| Dimensi | Nilai |
|---|---|
arch | amd64 |
node-version | lts/iron, lts/jod, lts/krypton |
include | arch: ppc64le dengan node-version: 20 |
| runner | ubuntu-latest |
| batas waktu job | 30 menit |
Sebelum test, workflow mengaktifkan Corepack, memasang dependency dengan npm ci, lalu memasang browser Playwright dengan npx playwright install --with-deps. Langkah terakhir menjalankan npm run build+test, jadi build dan seluruh rangkaian test ikut berjalan di CI. Masing-masing dari tiga langkah itu diberi timeout-minutes: 10. .github/workflows/ci-build-test.yml:33-4413
gantt
dateFormat mm:ss
axisFormat %M:%S
section run-test job, batas 30m
Install dependencies, npm ci :d1, 00:00, 10m
Install Playwright browsers :d2, after d1, 10m
Run the test suite, npm run build+test :d3, after d2, 10m
%% fig: Anggaran waktu job CI Build & Test
%% desc: Tiga step utama job run-test masing-masing dibatasi 10 menit, sementara seluruh job dibatasi 30 menit.Publikasi: npm dan Docker
Kedua workflow publikasi dipicu oleh event release bertipe published, bukan oleh push. publish-npm.yml meminta contents: read dan id-token: write. .github/workflows/publish-npm.yml:3-1314
sequenceDiagram
participant GH as release published
participant NPM as publish-npm.yml
participant DKR as publish-docker.yml
participant REG as registry npmjs dan Docker Hub
GH->>NPM: memicu job Publish: NPM
GH->>DKR: memicu job Publish: Docker
NPM->>NPM: corepack enable npm, npm ci
NPM->>REG: npm publish --provenance --access public
DKR->>DKR: ambil VERSION dari GITHUB_REF
DKR->>DKR: version_check dengan pola versi mayor minimal 2
alt versi mayor 2 ke atas
DKR->>REG: build-push linux/amd64 dan linux/arm64, tag VERSION dan latest
else versi mayor 1.x
DKR-->>DKR: step buildx, login, dan push dilewati
end
%% fig: Dua jalur publikasi dari satu release
%% desc: Satu event release memicu publish npm dan publish Docker; Docker hanya jalan untuk versi mayor 2 ke atas.publish-npm.yml menjalankan npm publish --provenance --access public dengan NODE_AUTH_TOKEN dari secrets.NPM_TOKEN, memakai Node 22 dan registry-url: 'https://registry.npmjs.org'. Flag --provenance itulah alasan permission id-token: write dibutuhkan. .github/workflows/publish-npm.yml:28-3115
publish-docker.yml mengambil versi dari GITHUB_REF lewat Extract version from release tag, lalu menguji $VERSION =~ ^([2-9]|[0-9]{2,})\.. Step Buildx, login, dan push hanya berjalan bila steps.version_check.outputs.docker_support == 'true'. .github/workflows/publish-docker.yml:19-3216
Push menghasilkan dua tag, faisalman/ua-parser-js:VERSION dan faisalman/ua-parser-js:latest, untuk linux/amd64 dan linux/arm64. Cache dipakai lewat registry faisalman/ua-parser-js:buildcache dengan mode=max. .github/workflows/publish-docker.yml:45-5717
Image dibangun multi-stage dari node:lts-alpine. Dependency dipasang dengan npm install --omit=dev, lalu src/, script/cli.js, dan node_modules disalin ke stage runtime. ENTRYPOINT menjalankan node ./script/cli.js, sehingga perintah di dalam image adalah CLI ua-parser-js; image tidak memuat dist/ karena cli.js membaca src/main/ua-parser. Dockerfile:1-14
⚠️ Rilis 1.x tidak menghasilkan image Docker.
version_checkhanya bernilaitrueuntuk versi mayor 2 ke atas, dan pada versi lain step push dilewati tanpa error, jadi job tetap hijau meski tidak ada image yang diunggah. .github/workflows/publish-docker.yml:19-3216
Paket npm yang terbit hanya memuat dist/*.?(m)js, dist/icons, dan src, dengan bin menunjuk ./script/cli.js. Artinya dist/ harus sudah ada sebelum npm publish, dan urutan itu dijamin oleh langkah build di workflow test. package.json:237-24318