Skip to content

Commit 2027389

Browse files
committed
wip
1 parent 152a85c commit 2027389

File tree

6 files changed

+282
-73
lines changed

6 files changed

+282
-73
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
# Composer
66
/vendor
7-
/vendor-dev
8-
/vendor-def
97
auth.json
108
composer.lock
119

packages/devlink/README.md

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,79 +7,60 @@ It is used to link the packages from the `moox` monorepo into a project. It runs
77
## Installation
88

99
```bash
10-
cp composer.json.example composer.json
1110
cp .env.example .env
1211
composer require moox/devlink
1312
php artisan vendor:publish --tag="devlink-config"
1413
```
1514

16-
## Usage
17-
18-
```bash
19-
php artisan moox:devlink
20-
```
21-
2215
## Screenshot
2316

2417
![Moox Devlink](./devlink.jpg)
2518

26-
## Preparation
19+
## How It Works
2720

28-
Before you can use this package, you need to prepare your project's `.gitignore` file.
21+
1. Prepare your project's `.gitignore` file:
2922

3023
```bash
24+
3125
# Ignore all files in packages/ (including symlinks)
3226
packages/*
3327
# Allow tracking of real directories inside packages/
3428
!packages/**/
3529
# Ensure empty directories can be committed
3630
!packages/*/.gitkeep
37-
# Ignore all files in packages-linked/ (for Windows)
38-
packages-linked/*
39-
```
40-
41-
## Configuration
42-
43-
The configuration is done in the `config/devlink.php` file.
44-
45-
```php
46-
47-
'packages_path' => 'packages',
48-
49-
'base_paths' => [
50-
base_path('../moox/packages'),
51-
],
52-
53-
'packages' => [
54-
'moox/tag',
55-
],
31+
# for windows
32+
/packageslocal/*
5633

5734
```
5835

59-
## Command
60-
61-
The devlink command will create a `packages` directory in the root of the project and symlink the packages from the configured base paths.
36+
2. Configure your paths and packages in the `config/devlink.php` file and the `.env` file, if needed (Windows users for example).
6237

63-
```bash
38+
3. When running `devlink:link`:
6439

65-
php artisan moox:devlink
40+
- Creates backup of original composer.json → composer.json.original
41+
- Creates symlinks for all configured packages
42+
- Updates composer.json with development configuration
43+
- Creates composer.json-deploy for production use
44+
- Asks to run `composer install`
45+
- Asks to run `php artisan optimize:clear`
46+
- Asks to run `php artisan queue:restart`
6647

67-
```
48+
4. When running `devlink:deploy`:
6849

69-
It will also update the `composer.json` file to include the packages in the `require` section and the `repositories` section.
50+
- Removes all symlinks
51+
- Deletes the packages folder, if empty
52+
- Restores production-ready composer.json from composer.json-deploy
7053

71-
Finally, it will run `composer update`.
54+
5. CI Safety Net - `deploy.sh`:
55+
- If composer.json-deploy exists in the repository:
56+
- The script will restore it as composer.json
57+
- Commit and push the change in GH action
58+
- This ensures no development configuration reaches production
7259

73-
### Changing branches
60+
## Changing branches
7461

7562
If you need to change the branches for ANY of the involved repositories, you just need to run the command again, it will automatically update the symlinks for the current branch.
7663

77-
```bash
78-
79-
php artisan moox:devlink
80-
81-
```
82-
8364
> ⚠️ **Important**
8465
> If you forget to run the command, when CHANGING BRANCHES ON ANY OF THE REPOS, you will surely run into a 500 error, that drives you nuts.
8566
@@ -101,6 +82,17 @@ On Windows there are most probably some issues with the symlinks. If you run int
10182

10283
Devlink will then link the packages into the `packages-linked` folder.
10384

85+
## Roadmap
86+
87+
- [ ] Test on Mac
88+
- [ ] Test on Windows
89+
- [ ] Test Deployment on Mac
90+
- [ ] Test Deployment on Windows
91+
- [ ] Implement automatic Deployment
92+
- [ ] Implement all 3 types of packages
93+
- [ ] If package is a symlink itself, ...?
94+
- [ ] If package is in multiple base paths...?
95+
10496
## Security Vulnerabilities
10597

10698
Please review [our security policy](https://github.com/mooxphp/moox/security/policy) on how to report security vulnerabilities.

packages/devlink/config/devlink.php

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,38 @@
11
<?php
22

33
return [
4+
5+
// User-specific path from .env
6+
'packages_path' => env('DEVLINK_PACKAGES_PATH', 'packages'),
7+
8+
// The base paths to the packages, project or branch-wise
49
'base_paths' => [
510
base_path('../moox/packages'),
611
],
712

13+
// The internal packages need to be copied on deploy, project or branch-wise,
14+
'copy_packages' => [
15+
// 'builder-pro',
16+
],
17+
18+
// The packages that need to be removed on deploy,project or branch-wise
19+
'skip_packages' => [
20+
'devlink',
21+
],
22+
23+
// The packages that are installed from Packagist on deploy, project or branch-wise
824
'packages' => [
9-
'audit',
25+
// 'audit',
1026
// 'backup-server-ui',
11-
'builder',
12-
// 'builder-pro',
27+
// 'builder',
1328
// 'category',
1429
// 'core',
1530
// 'connect',
1631
// 'data',
1732
// 'devops',
1833
// 'expiry',
19-
'flags',
20-
'jobs',
34+
// 'flags',
35+
// 'jobs',
2136
// 'login-link',
2237
// 'localization',
2338
// 'media',
@@ -28,7 +43,7 @@
2843
// 'press',
2944
// 'security',
3045
// 'sync',
31-
// 'tag',
46+
'tag',
3247
// 'trainings',
3348
// 'user',
3449
// 'user-device',

packages/devlink/deploy.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
if [ -f "composer.json-deploy" ]; then
4+
# Remove all symlinks from /packages
5+
find packages -type l -delete
6+
# Remove the packages folder if empty
7+
if [ -z "$(ls -A packages)" ]; then
8+
rm packages
9+
fi
10+
cp composer.json-deploy composer.json
11+
composer install
12+
fi
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
<?php
2+
3+
namespace Moox\Devlink\Commands;
4+
5+
use Illuminate\Console\Command;
6+
7+
class DeployPackages extends Command
8+
{
9+
protected $signature = 'devlink:deploy';
10+
11+
protected $description = 'Symlink Moox packages into the project from multiple base paths and ensure composer.json is updated';
12+
13+
protected array $basePaths;
14+
15+
protected array $packages;
16+
17+
protected string $composerJsonPath;
18+
19+
protected string $packagesPath;
20+
21+
public function __construct()
22+
{
23+
parent::__construct();
24+
25+
$this->basePaths = config('devlink.base_paths', []);
26+
$this->packages = config('devlink.packages', []);
27+
28+
if (empty($this->basePaths)) {
29+
$this->warn('No base paths configured in config/devlink.php');
30+
}
31+
32+
if (empty($this->packages)) {
33+
$this->warn('No packages configured in config/devlink.php');
34+
}
35+
36+
$this->composerJsonPath = base_path('composer.json');
37+
$this->packagesPath = config('devlink.packages_path', base_path('packages'));
38+
}
39+
40+
public function handle(): void
41+
{
42+
$this->art();
43+
$this->hello();
44+
$this->checks();
45+
$this->removeAllSymlinks();
46+
$this->removePackagesDirectoryIfEmpty();
47+
$this->restoreComposerJson();
48+
$this->runComposerUpdate();
49+
$this->optimizeClear();
50+
$this->queueRestart();
51+
$this->goodbye();
52+
}
53+
54+
public function art(): void
55+
{
56+
$this->info('
57+
58+
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓
59+
▓▓▒░░▒▓▓▒▒░░░░░░▒▒▓▓▓▒░░░░░░░▒▓▓ ▓▓▓▓▒░░░░░░░▒▓▓▓▓ ▓▓▓▓▓▒░░░░░░░▒▒▓▓▓▓▓▒▒▒▒▓▓ ▓▓▓▒▒▒▒▓▓
60+
▓▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓▒░░░░░░░░░░░░░▒▓▓▓ ▓▓▓▓▒░░░░░░░░░░░░░▒▓▓▓░░░░░▒▓▓ ▓▓▒░░░░░▓▓
61+
▓▒░░░░░░▒▓▓▓▓▒░░░░░░░▒▓▓▓▓░░░░░▒▓▓▓░░░░░▒▓▓▓▓▒░░░░░░░▓▓▓▓░░░░░░▒▓▓▓▓▓░░░░░░▒▓▓░░░░░▒▓▓▓▓▓░░░░░▒▓▓
62+
▓▒░░░░▓▓▓▓ ▓▓░░░░░▓▓▓ ▓▓▓░░░░▒▓▓░░░░▒▓▓▓ ▓▓▓▓░░░░░▓░░░░░░▓▓▓▓ ▓▓▓▒░░░░▓▓▓▒░░░░░▓▓▓░░░░░▓▓▓
63+
▓▒░░░░▒▓ ▓▓░░░░░▓▓ ▓▓░░░░▒▓░░░░▒▓▓ ▓▓▓░░▒░░░░░▓▓▓ ▓▓░░░░▒▓▓▓▓░░░░░░░░░░░▓▓
64+
▓▒░░░░▒▓ ▓▓░░░░░▓▓ ▓▓░░░░▒▓░░░░▒▓ ▓▓▓░░░░░▒▓▓ ▓▓▒░░░░▓ ▓▓▓░░░░░░░░░▓▓
65+
▓▒░░░░▒▓ ▓▓░░░░░▓▓ ▓▓░░░░▒▓░░░░▒▓▓ ▓▓▒░░░░░▒░░▒▓▓ ▓▓░░░░▒▓▓▓▒░░░░░▒░░░░░▒▓
66+
▓▒░░░░▒▓ ▓▓░░░░░▓▓ ▓▓░░░░▒▓▓░░░░▒▓▓▓ ▓▓▓▒░░░░░▒▒░░░░░▒▓▓▓ ▓▓▓░░░░░▓▓▓░░░░░▒▓▓▓░░░░░▒▓▓
67+
▓▒░░░░▒▓ ▓▓░░░░░▓▓ ▓▓░░░░▒▓▓▓░░░░░░▒▒▓▓▒░░░░░░▒▓▓▓▓░░░░░░░▒▒▓▓▒░░░░░░▓▓▓░░░░░▒▓▓▓▓▓▒░░░░░▓▓
68+
▓▒░░░░▒▓ ▓▓░░░░░▓▓ ▓▓░░░░▒▓▓▓▓▒░░░░░░░░░░░░░▒▓▓▓ ▓▓▓▓▒░░░░░░░░░░░░░▒▓▓▒░░░░░▓▓▓ ▓▓▒░░░░░▒▓
69+
▓▓░░░▒▓▓ ▓▓▒░░░▒▓▓ ▓▓░░░░▓▓ ▓▓▓▓▒░░░░░░▒▒▓▓▓▓ ▓▓▓▓▓▒▒░░░░░▒▒▓▓▓▓▓░░░░▒▓▓ ▓▓▓░░░░▒▓
70+
▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓
71+
72+
');
73+
}
74+
75+
private function hello(): void
76+
{
77+
$this->info('Hello, I will prepare your project for deployment.');
78+
}
79+
80+
private function checks(): void
81+
{
82+
$this->line("\nConfiguration:");
83+
$this->line('Base paths:');
84+
if (empty($this->basePaths)) {
85+
$this->warn('- No base paths configured');
86+
} else {
87+
foreach ($this->basePaths as $path) {
88+
$resolvedPath = $this->resolvePath($path);
89+
$this->line("- $path");
90+
$this->line("$resolvedPath".(is_dir($resolvedPath) ? ' (exists)' : ' (not found)'));
91+
}
92+
}
93+
94+
$this->line("\nConfigured packages:");
95+
if (empty($this->packages)) {
96+
$this->warn('No packages configured in config/devlink.php');
97+
} else {
98+
foreach ($this->packages as $package) {
99+
$this->line("- $package");
100+
}
101+
}
102+
103+
$this->line('');
104+
}
105+
106+
private function removeAllSymlinks(): void
107+
{
108+
if (is_dir($this->packagesPath)) {
109+
foreach (scandir($this->packagesPath) as $item) {
110+
if ($item !== '.' && $item !== '..' && is_link("$this->packagesPath/$item")) {
111+
unlink("$this->packagesPath/$item");
112+
}
113+
}
114+
}
115+
}
116+
117+
private function removePackagesDirectoryIfEmpty(): void
118+
{
119+
if (is_dir($this->packagesPath) && count(scandir($this->packagesPath)) === 2) {
120+
rmdir($this->packagesPath);
121+
}
122+
}
123+
124+
private function restoreComposerJson(): void
125+
{
126+
$deployFile = $this->composerJsonPath.'-deploy';
127+
if (! file_exists($deployFile)) {
128+
$this->error('composer.json-deploy not found!');
129+
130+
return;
131+
}
132+
133+
unlink($this->composerJsonPath);
134+
rename($deployFile, $this->composerJsonPath);
135+
$this->info('Restored composer.json from composer.json-deploy');
136+
}
137+
138+
private function runComposerUpdate(): void
139+
{
140+
if ($this->confirm('Run composer update now?', true)) {
141+
$output = [];
142+
$returnVar = 0;
143+
exec('composer update 2>&1', $output, $returnVar);
144+
145+
if ($returnVar !== 0) {
146+
$this->error('Composer update failed: '.implode("\n", $output));
147+
148+
return;
149+
}
150+
151+
$this->info('Composer update completed successfully');
152+
} else {
153+
$this->info("Please run 'composer update' manually");
154+
}
155+
}
156+
157+
private function optimizeClear(): void
158+
{
159+
if ($this->confirm('Run artisan optimize:clear now?', true)) {
160+
$this->info('Clearing cache...');
161+
$this->call('optimize:clear');
162+
$this->info('Cache cleared successfully');
163+
} else {
164+
$this->info("Please run 'artisan optimize:clear' manually");
165+
}
166+
}
167+
168+
private function queueRestart(): void
169+
{
170+
if ($this->confirm('Run queue:restart now?', false)) {
171+
$this->info('Restarting queue...');
172+
$this->call('queue:restart');
173+
}
174+
}
175+
176+
private function goodbye(): void
177+
{
178+
$this->info('Have a nice dev!');
179+
}
180+
181+
private function resolvePath(string $path): string
182+
{
183+
return str_starts_with($path, '~/') ? str_replace('~', getenv('HOME'), $path) : rtrim(realpath($path) ?: $path, '/');
184+
}
185+
}

0 commit comments

Comments
 (0)