Kebijakan Versioning
Halaman ini menjelaskan arti version number chocoalano/panel, bagian package mana yang dicakup oleh version tersebut, dan constraint seperti apa yang sebaiknya ditulis pada composer.json. Gunakan panduan ini sebelum mem-pin dependency constraint, sebelum mendeklarasikan requiresPanel pada plugin, atau ketika Anda perlu menentukan apakah sebuah upgrade diperbolehkan mematahkan aplikasi.
Contoh minimal yang dapat langsung digunakan
composer require chocoalano/panel
composer show chocoalano/panel
composer outdated chocoalano/panel2
3
composer show menampilkan version yang benar-benar di-resolve. String tersebut — bukan Git branch dan bukan heading pada CHANGELOG.md — adalah version yang dibahas di halaman ini. Framework juga membaca value yang sama ketika plugin mendeklarasikan constraint.
Semantic versioning dan posisi project saat ini
CHANGELOG.md menyatakan contract versioning pada header-nya:
The format follows Keep a Changelog, and this project adheres to Semantic Versioning.Tag yang sudah dipublikasikan sejauh ini adalah v0.1.0, v0.1.1, v0.1.2, dan v0.1.4, sehingga package masih berada pada seri 0.x. (v0.1.3 memang tidak pernah dibuat; gap pada sequence berarti version tersebut tidak ada, bukan version yang gagal Anda temukan.) git tag pada checkout repository adalah daftar authoritative; daftar di dokumentasi hanya snapshot. Semantic versioning memperlakukan 0.x sebagai rentang khusus: minor release pada 0.x diperbolehkan breaking. Composer memahami aturan ini dan menerapkan perilaku caret yang sesuai.
git tag # in a checkout of the repository
composer show chocoalano/panel | grep versions2
| Constraint | Range yang dapat di-resolve | Kemungkinan breaking change |
|---|---|---|
^0.1 | >=0.1.0 <0.2.0 | di dalam 0.1.x: tidak |
^0.1.2 | >=0.1.2 <0.2.0 | di dalam 0.1.x: tidak |
~0.1.2 | >=0.1.2 <0.2.0 | sama dengan caret pada 0.x |
0.1.* | >=0.1.0 <0.2.0 | sama |
>=0.1 | version lebih baru apa pun, termasuk 1.x | ya, tanpa boundary otomatis |
dev-main | apa pun isi main saat ini | ya, pada setiap composer update |
Caret adalah default yang tepat dan itulah yang ditulis oleh composer require chocoalano/panel. Dua pola yang perlu dihindari untuk aplikasi normal adalah >= dan dev-main: yang pertama memasukkan project ke semua breaking release di masa depan tanpa boundary, sedangkan yang kedua membuat hasil composer update tidak reproducible.
Setelah 1.0.0, ^1.0 berperilaku seperti caret pada package stabil lainnya — minor dan patch diperbolehkan, major breaking tidak. Selama masih di 0.x, baca Breaking changes sebelum setiap minor upgrade.
Apa yang dicakup version number
.gitattributes menentukan isi release yang benar-benar diterima aplikasi. Semua yang diberi export-ignore tidak ada pada installed package, sehingga tidak dapat menjadi bagian dari compatibility promise package:
/.github export-ignore
/docs export-ignore
/examples export-ignore
/tests export-ignore
/frontend export-ignore
/CHANGELOG.md export-ignore
/package.json export-ignore
/vite.config.ts export-ignore
/phpstan.neon export-ignore
/pint.json export-ignore2
3
4
5
6
7
8
9
10
Yang tersisa — src, config, database, stubs, dan resources — adalah shipped surface. Di dalam surface tersebut, version number mencakup:
| Dicakup oleh version number | Alasan |
|---|---|
Class PandaPanel\* yang disebut dokumentasi | Aplikasi memanggilnya secara langsung |
Config key pada config/panda-panel.php | panels, register_routes, register_web_middleware, register_guest_redirect, home_redirect, load_migrations, integrations, frontend |
| Publish tags | panda-panel, panda-panel-config, panda-panel-assets, panda-panel-migrations, panda-panel-stubs |
| Nama Artisan command dan option-nya | panel:install, panel:assets, panel:cache, panel:clear, panel:icons, panel:plugins, panel:publish, panel:user, serta lima generator make:panel* |
| Route names | panel.{id}.* |
PandaPanel\Testing\* dan global helper function | Test suite aplikasi memanggilnya langsung |
| Serialized shape yang dibagikan panel ke Vue | Prop SharePanelData merupakan contract yang dibaca customised frontend |
Beberapa hal tidak dicakup, masing-masing dengan alasan yang jelas:
| Tidak dicakup | Alasan |
|---|---|
| Published Vue dan TypeScript files | Setelah dipublish, file tersebut disalin ke aplikasi dan menjadi milik aplikasi. Package version tidak dapat menjamin state file yang sudah Anda edit; fungsi itu dimiliki .panel-assets.json |
Semua file yang export-ignore | File tersebut memang tidak ada pada installed package. Frontend toolchain, test suite, examples/, dan dokumentasi digunakan untuk mengembangkan repository |
| Isi generator stub | stubs/panel adalah scaffolding. Scaffold yang tidak pernah berubah juga tidak pernah dapat diperbaiki. Publish dengan --tag=panda-panel-stubs jika ingin membekukan salinan sendiri |
| npm package | @chocoalano/panel menggunakan "private": true, version 0.0.0, dan tidak pernah dipublish. Component mencapai aplikasi melalui vendor:publish |
Dependency range
Daftar berikut berasal dari composer.json. Setiap dependency menggunakan range, bukan pin, karena library yang mem-pin seluruh dependency justru sulit dipasang bersama package lain:
"require": {
"php": "^8.2",
"ext-json": "*",
"ext-zip": "*",
"composer-runtime-api": "^2.2",
"composer/semver": "^3.0",
"inertiajs/inertia-laravel": "^3.0",
"laravel/framework": "^12.0|^13.0",
"laravel/fortify": "^1.37.2",
"symfony/finder": "^7.0|^8.0"
}2
3
4
5
6
7
8
9
10
11
"minimum-stability": "stable",
"prefer-stable": true2
minimum-stability: stable berarti composer require chocoalano/panel pada aplikasi tidak akan menarik dev atau beta dependency karena kebutuhan package ini.
Kedua ujung setiap range diuji. CI me-resolve dependency menggunakan --prefer-lowest dan juga --prefer-stable, total sepuluh job, karena dependency yang hanya bekerja pada version terbaru berarti constraint-nya terlalu longgar atau salah. Support matrix lengkap tersedia di Compatibility, sedangkan job CI dijelaskan di CI matrix.
composer-runtime-api dibutuhkan karena ada class yang membaca installed-package data milik Composer pada runtime, yang dijelaskan pada bagian berikut.
Menanyakan version yang benar-benar terinstal
composer show chocoalano/panel # version, source, requires
composer why chocoalano/panel # which of your constraints pulled it
composer why-not chocoalano/panel ^1 # why a newer one will not resolve
php artisan panel:plugins # plugins, per panel, with their versions
php artisan about --only=environment # PHP and Laravel, for a bug report2
3
4
5
Di PHP, version dibaca dari Composer, bukan dari constant milik package. Version string yang ditulis manual adalah value yang mudah lupa diperbarui; package yang mengaku 1.2.0 ketika 1.4.1 sebenarnya terinstal lebih buruk daripada package yang tidak menebak version sama sekali.
use Composer\InstalledVersions;
InstalledVersions::getPrettyVersion('chocoalano/panel'); // e.g. '0.1.4' — whatever is installed
InstalledVersions::isInstalled('chocoalano/panel'); // true2
3
4
getPrettyVersion() melempar exception untuk package yang tidak ada pada instalasi. Ini bukan detail kecil: failure mode inilah yang pernah dipicu oleh rename package dan didokumentasikan pada Migrasi nama package.
Mendeklarasikan version requirement dari plugin
Plugin adalah code yang masuk ke panel lalu menambahkan resource, page, widget, atau route. Ketika plugin rusak, dua pertanyaan pertama selalu: plugin mana dan version berapa. Keduanya tidak dapat dijawab hanya dari class name. PandaPanel\Plugins\PluginMetadata menyediakan metadata yang dibutuhkan.
use PandaPanel\Plugins\Plugin;
use PandaPanel\Plugins\PluginMetadata;
final class BillingPlugin extends Plugin
{
public function id(): string
{
return 'billing';
}
public function metadata(): PluginMetadata
{
return new PluginMetadata(
name: 'Billing',
package: 'acme/panda-billing',
requiresPanel: '^0.1',
url: 'https://github.com/acme/panda-billing',
);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PandaPanel\Plugins\PluginMetadata adalah class final readonly:
public function __construct(
public string $name,
public ?string $package = null,
public ?string $requiresPanel = null,
public ?string $url = null,
) {}2
3
4
5
6
| Parameter | Tipe | Default | Arti |
|---|---|---|---|
name | string | wajib | Nama yang mudah dibaca manusia untuk report |
package | string|null | null | Composer package milik plugin, digunakan untuk version lookup |
requiresPanel | string|null | null | Constraint bergaya Composer terhadap framework ini |
url | string|null | null | Lokasi dokumentasi atau halaman plugin |
| Method | Signature | Mengembalikan |
|---|---|---|
version | version(): ?string | Installed version dari package melalui Composer. null jika package adalah null, dan null jika Composer tidak mengenal nama package |
toArray | toArray(): array{name, package, version, requiresPanel, url} | Shape yang ditampilkan panel:plugins |
$metadata = new PluginMetadata(name: 'Billing', package: 'acme/panda-billing');
$metadata->version(); // '2.1.0', or null for a plugin that lives in the application
$metadata->toArray(); // ['name' => 'Billing', 'package' => 'acme/panda-billing', 'version' => '2.1.0', …]2
3
4
Version null adalah jawaban yang valid. Plugin milik project dapat hidup langsung di aplikasi dan mengikuti version aplikasi. Nama package yang salah dilaporkan sebagai unknown, bukan fatal error, karena kesalahan metadata tidak selalu layak menghentikan boot aplikasi.
Cara constraint diperiksa
PandaPanel\Plugins\PluginCompatibility berjalan ketika plugin diregistrasikan — titik paling awal saat installed version sudah diketahui dan titik terakhir sebelum plugin mulai mengubah panel.
public static function assert(
PanelPlugin $plugin,
string $panelId,
?string $installed = null,
): void2
3
4
5
| Parameter | Tipe | Default | Arti |
|---|---|---|---|
$plugin | PandaPanel\Contracts\PanelPlugin | wajib | Dibaca untuk metadata()->requiresPanel, metadata()->name, dan id() |
$panelId | string | wajib | Dicantumkan pada exception karena plugin yang sama dapat terpasang di beberapa panel |
$installed | string|null | null | Version framework yang diperiksa; default-nya version dari Composer |
Method melempar PandaPanel\Exceptions\PanelRegistrationException ketika constraint tidak terpenuhi dan return tanpa output jika compatibility valid. Mengirim $installed secara eksplisit adalah cara test memeriksa refusal tanpa harus benar-benar menginstal version lain:
use PandaPanel\Exceptions\PanelRegistrationException;
use PandaPanel\Plugins\PluginCompatibility;
// BillingPlugin declares requiresPanel: '^0.1', which is >=0.1.0 <0.2.0.
PluginCompatibility::assert(new BillingPlugin, 'admin', '0.1.5'); // satisfied — returns
expect(fn () => PluginCompatibility::assert(new BillingPlugin, 'admin', '0.2.0'))
->toThrow(PanelRegistrationException::class);2
3
4
5
6
7
8
9
Constraint dievaluasi oleh Composer\Semver\Semver::satisfies(), sehingga format yang valid sama dengan constraint Composer: ^0.1, >=0.1.2 <0.3, 0.1.*, atau ^1.0 || ^2.0.
Tiga kondisi yang dilewati
Ketiganya memang berarti tidak ada version comparison yang dapat dilakukan, dan menjadikannya failure akan menghasilkan false refusal:
| Kondisi | Hasil | Alasan |
|---|---|---|
requiresPanel adalah null | lolos | Sebagian besar plugin tidak memiliki constraint; belum menyatakan compatibility bukan berarti otomatis incompatible |
| Framework tidak diinstal sebagai Composer package | lolos | Path repository, git checkout, atau test suite repository ini tidak memiliki package version untuk dibandingkan |
Version berupa dev-* atau mengandung no-version-set | lolos | Constraint tidak dapat dievaluasi terhadap branch, dan menolak semua plugin pada development checkout akan membuat ecosystem sulit diuji |
Nama package yang digunakan untuk lookup disimpan sebagai private constant dan harus sama persis dengan composer.json:
private const PACKAGE = 'chocoalano/panel';Nama yang tidak dikenal Composer membuat getPrettyVersion() melempar exception. Class membaca kondisi tersebut sebagai "framework tidak diinstal sebagai package" lalu menghasilkan null, sedangkan version null melewati semua constraint. Ini pernah terjadi saat rename package. Sekarang PluginTest membandingkan constant dengan name di composer.json agar failure tersebut tidak dapat terulang dalam bentuk yang sama.
Frontend memiliki dependency version sendiri
Komponen panel merupakan Vue SFC yang dibuild oleh Vite milik aplikasi, menggunakan dependency tree aplikasi. package.json pada repository mendeklarasikan range yang menjadi target component. File tersebut adalah source of truth; php artisan panel:install membaca daftar yang sama untuk memberi tahu aplikasi apa yang harus diinstal, sehingga code dan installer seharusnya tidak memiliki daftar dependency terpisah.
"engines": { "node": ">=20.19" },
"dependencies": {
"@inertiajs/vue3": "^3.0.0",
"@lucide/vue": "^1.31.0",
"@tanstack/vue-table": "^9.0.0",
"reka-ui": "^2.0.0",
"tailwindcss": "^4.1.0",
"vue": "^3.5.0"
}2
3
4
5
6
7
8
9
Toolchain tersebut tidak ikut menjadi lockfile aplikasi. package.json, package-lock.json, Vite config, tsconfig, dan lint config diberi export-ignore, sehingga aplikasi menginstal dependency berdasarkan range, bukan berdasarkan lockfile milik repository framework.
npm ls vue tailwindcss @inertiajs/vue3 reka-ui --depth=0Published asset memiliki version terpisah
composer update memindahkan vendor/chocoalano/panel, tetapi tidak memindahkan resources/js/panel karena setelah publish file tersebut menjadi milik aplikasi. "Version" dari published asset direkam oleh .panel-assets.json menggunakan hash file pada saat dipublish lalu disinkronkan dengan panel:assets:
composer update chocoalano/panel
php artisan panel:assets # what is behind, what you changed, what conflicts
php artisan panel:assets --update # write only the files you have never touched
npm run build2
3
4
Karena itu package version dan frontend version adalah dua pertanyaan berbeda pada installed application. Manifest asset menjelaskan mekanisme version kedua secara lengkap.
Catatan
- Minor release pada
0.xdapat breaking. Sampai1.0.0, baca Breaking changes sebelum minor bump. Caret melindungi Anda secara default;>=tidak. CHANGELOG.mdtidak tersedia pada installed package. File tersebut diberiexport-ignore, sehinggavendor/chocoalano/panel/CHANGELOG.mdmemang tidak ada. Baca changelog dari repository — lihat Changelog.- Tidak ada constant
Panel::VERSION. Version sengaja berasal dari Composer. Constant version mudah lupa diperbarui. requiresPanelplugin tidak dipaksakan pada git checkout.dev-maindan1.0.0+no-version-setsama-sama melewati check. Constraint yang seharusnya ditolak di aplikasi dapat lolos pada test suite repository; kirim$installedsecara eksplisit untuk menguji refusal.composer.lockadalah catatan version yang benar-benar berjalan pada aplikasi. Commit file tersebut. Range dicomposer.jsonmenyatakan apa yang diperbolehkan, sedangkan lockfile menyatakan apa yang dipakai.- Laravel floor ditentukan oleh keamanan, bukan preferensi. Laravel 11 tidak didukung karena seluruh release 11.x terkena unpatched advisory yang membuat Composer menolak resolve. Lihat Compatibility.
Lihat juga
- Panduan upgrade — prosedur berpindah antar-version
- Breaking changes — perubahan yang mematahkan compatibility beserta fix terkecil
- Changelog — organisasi release note
- Release checklist — langkah sebelum tag dibuat
- Manifest asset — versioning published frontend
- Migrasi nama package — rename dan dampaknya terhadap version lookup
- Compatibility, Requirements
- Plugin compatibility, Plugin metadata
- CI matrix
panel:plugins