From 5b8ec2b6e4644a8fc960a9712ac3723cdff93c11 Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Tue, 1 Apr 2025 23:07:01 +0300 Subject: [PATCH 01/12] Replacing the documentation generator on Jetbrains Writerside --- .github/workflows/docs.yml | 53 ---- docs/.vuepress/.gitignore | 4 - docs/.vuepress/config.js | 119 -------- docs/.vuepress/public/CNAME | 1 - .../public/fonts/Nunito-SemiBold.woff2 | Bin 56088 -> 0 bytes docs/.vuepress/public/images/logo.svg | 63 ---- docs/.vuepress/styles/_fonts.scss | 9 - docs/.vuepress/styles/index.scss | 17 -- docs/extras/database-data-dumper.md | 31 -- docs/getting-started/installation.md | 27 -- docs/guide/basic.md | 66 ---- docs/guide/creating.md | 154 ---------- docs/guide/customize-stub.md | 11 - docs/guide/rollback.md | 71 ----- docs/guide/running.md | 288 ------------------ docs/guide/status.md | 8 - docs/helpers/artisan.md | 18 -- docs/helpers/events.md | 54 ---- docs/helpers/execution-status.md | 100 ------ docs/index.md | 42 --- docs/upgrade-guide/3.x.md | 125 -------- docs/upgrade-guide/4.x.md | 99 ------ docs/upgrade-guide/5.x.md | 35 --- docs/upgrade-guide/6.x.md | 198 ------------ docs/upgrade-guide/index.md | 6 - package.json | 32 -- 26 files changed, 1631 deletions(-) delete mode 100644 .github/workflows/docs.yml delete mode 100644 docs/.vuepress/.gitignore delete mode 100644 docs/.vuepress/config.js delete mode 100644 docs/.vuepress/public/CNAME delete mode 100644 docs/.vuepress/public/fonts/Nunito-SemiBold.woff2 delete mode 100644 docs/.vuepress/public/images/logo.svg delete mode 100644 docs/.vuepress/styles/_fonts.scss delete mode 100644 docs/.vuepress/styles/index.scss delete mode 100644 docs/extras/database-data-dumper.md delete mode 100644 docs/getting-started/installation.md delete mode 100644 docs/guide/basic.md delete mode 100644 docs/guide/creating.md delete mode 100644 docs/guide/customize-stub.md delete mode 100644 docs/guide/rollback.md delete mode 100644 docs/guide/running.md delete mode 100644 docs/guide/status.md delete mode 100644 docs/helpers/artisan.md delete mode 100644 docs/helpers/events.md delete mode 100644 docs/helpers/execution-status.md delete mode 100644 docs/index.md delete mode 100644 docs/upgrade-guide/3.x.md delete mode 100644 docs/upgrade-guide/4.x.md delete mode 100644 docs/upgrade-guide/5.x.md delete mode 100644 docs/upgrade-guide/6.x.md delete mode 100644 docs/upgrade-guide/index.md delete mode 100644 package.json diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index a9ed469e..00000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: docs - -on: - push: - branches: - - main - workflow_run: - workflows: - - changelog - types: - - completed - workflow_dispatch: - -permissions: write-all - -jobs: - generate: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - - - name: Cache dependencies - uses: actions/cache@v4 - id: npm-cache - with: - path: | - **/node_modules - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} - - - name: Install dependencies - run: npm i - - - name: Build VuePress site - run: npm run build - - - name: Deploy to GitHub Pages - uses: crazy-max/ghaction-github-pages@v4.1.0 - with: - target_branch: gh-pages - build_dir: docs/.vuepress/dist - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/.vuepress/.gitignore b/docs/.vuepress/.gitignore deleted file mode 100644 index 1d57eb52..00000000 --- a/docs/.vuepress/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.cache/ -.temp/ - -dist/ diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js deleted file mode 100644 index dc72e049..00000000 --- a/docs/.vuepress/config.js +++ /dev/null @@ -1,119 +0,0 @@ -import fs from 'fs' -import path from 'path' -import dotenv from 'dotenv' - -import {viteBundler} from '@vuepress/bundler-vite' -import {defaultTheme} from '@vuepress/theme-default' -import {defineUserConfig} from 'vuepress' - -dotenv.config() - -function getChildren(folder, sort = 'asc') { - const extension = ['.md'] - const names = ['index.md', 'readme.md'] - - const dir = `${__dirname}/../${folder}` - - return fs - .readdirSync(path.join(dir)) - .filter(item => fs.statSync(path.join(dir, item)).isFile() && !names.includes(item.toLowerCase()) && extension.includes(path.extname(item))) - .sort((a, b) => { - a = resolveNumeric(a) - b = resolveNumeric(b) - - if (a < b) return sort === 'asc' ? -1 : 1 - if (a > b) return sort === 'asc' ? 1 : -1 - - return 0 - }).map(item => `/${folder}/${item}`) -} - -function resolveNumeric(value) { - const sub = value.substring(0, value.indexOf('.')) - - const num = Number(sub) - - return isNaN(num) ? value : num -} - -const hostname = 'deploy-operations.dragon-code.pro' - -export default defineUserConfig({ - bundler: viteBundler(), - - lang: 'en-US', - title: 'Laravel Deploy Operations', - description: 'Performing any actions during the deployment process', - - head: [['link', {rel: 'icon', href: `https://${hostname}/images/logo.svg`}]], - - theme: defaultTheme({ - hostname, - base: '/', - - logo: `https://${hostname}/images/logo.svg`, - - repo: 'https://github.com/TheDragonCode/laravel-deploy-operations', - repoLabel: 'GitHub', - docsRepo: 'https://github.com/TheDragonCode/laravel-deploy-operations', - docsBranch: 'main', - docsDir: 'docs', - - contributors: false, - editLink: true, - - navbar: [ - { - text: '6.x', - children: [ - { - text: '6.x', - link: '/getting-started/installation.md' - }, - { - text: '5.x', - link: 'https://github.com/TheDragonCode/laravel-deploy-operations/blob/5.x/docs/index.md' - }, { - text: '4.x', - link: 'https://github.com/TheDragonCode/laravel-deploy-operations/blob/4.x/docs/index.md' - }, { - text: '3.x', - link: 'https://github.com/TheDragonCode/laravel-deploy-operations/blob/3.x/docs/index.md' - }, - ] - }], - - sidebarDepth: 1, - - sidebar: [ - { - text: 'Getting Started', children: [ - '/index.md', - '/getting-started/installation.md', - '/guide/basic.md', - '/upgrade-guide/index.md' - ] - }, - { - text: 'Guide', - children: [ - '/guide/running.md', - '/guide/creating.md', - '/guide/status.md', - '/guide/rollback.md', - '/guide/customize-stub.md', - ] - }, - { - text: 'Helpers', - children: getChildren('helpers') - }, - { - text: 'Extras', - children: [ - '/extras/database-data-dumper.md' - ] - } - ] - }) -}) diff --git a/docs/.vuepress/public/CNAME b/docs/.vuepress/public/CNAME deleted file mode 100644 index fc3c950d..00000000 --- a/docs/.vuepress/public/CNAME +++ /dev/null @@ -1 +0,0 @@ -deploy-operations.dragon-code.pro diff --git a/docs/.vuepress/public/fonts/Nunito-SemiBold.woff2 b/docs/.vuepress/public/fonts/Nunito-SemiBold.woff2 deleted file mode 100644 index 0f41dd933127d332e2837a8a2e03a846b32c8b6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56088 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 diff --git a/docs/.vuepress/public/images/logo.svg b/docs/.vuepress/public/images/logo.svg deleted file mode 100644 index 96a5a57a..00000000 --- a/docs/.vuepress/public/images/logo.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - diff --git a/docs/.vuepress/styles/_fonts.scss b/docs/.vuepress/styles/_fonts.scss deleted file mode 100644 index 8299f17b..00000000 --- a/docs/.vuepress/styles/_fonts.scss +++ /dev/null @@ -1,9 +0,0 @@ -@charset "UTF-8"; - -@font-face { - font-family: 'Nunito'; - src: local('Nunito'), url(/fonts/Nunito-SemiBold.woff2) format('woff2'); - font-weight: 600; - font-style: normal; - font-display: swap; -} diff --git a/docs/.vuepress/styles/index.scss b/docs/.vuepress/styles/index.scss deleted file mode 100644 index d3b35c71..00000000 --- a/docs/.vuepress/styles/index.scss +++ /dev/null @@ -1,17 +0,0 @@ -@charset "UTF-8"; - -@import "fonts"; - -:root { - --content-width: 800px; -} - -.code-group { - &__nav-tab { - font-family: Nunito, system-ui, sans-serif; - } -} - -.line { - color: rgb(235 235 245 / 86%); -} diff --git a/docs/extras/database-data-dumper.md b/docs/extras/database-data-dumper.md deleted file mode 100644 index c78f0e5f..00000000 --- a/docs/extras/database-data-dumper.md +++ /dev/null @@ -1,31 +0,0 @@ -# Database Dumper - -As you build your application, you may accumulate more and more migrations over time. -This can lead to your `database/migrations` directory becoming bloated with potentially hundreds of migrations. -If you would like, you may "squash" your migrations into a single SQL file. -To get started, execute the `schema:dump` command: - -```bash -php artisan schema:dump -``` - -You can read more about the operation of this console command in -the [official documentation](https://laravel.com/docs/11.x/migrations#squashing-migrations). - -Here we mention this console command because operations tend to save the execution state in order to prevent re-runs -where this is not explicitly allowed. -But if you run sequentially the console commands `php artisan schema:dump` and `php artisan migrate:fresh`, you will see -that all actions will be called again. - -This is due to the fact that the dump mechanism saves the contents of just one table - `migrations`. - -To solve this problem, there is a [Database Data Dumper](https://github.com/TheDragonCode/laravel-data-dumper) -project that allows you to specify a list of tables required for export to a dump. - -In addition to those that you can easily specify in its configuration file, we recommend that you also specify -the `operations` table from this project in order to save the state of the operations when performing a clean deployment -of the database from a dump. - -```bash -composer require dragon-code/laravel-data-dumper --dev -``` diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md deleted file mode 100644 index 4ec4730e..00000000 --- a/docs/getting-started/installation.md +++ /dev/null @@ -1,27 +0,0 @@ -# Installation - -## Install the package - -All you need to do to get started is add `Deploy Operations` to your [composer](https://getcomposer.org) dependencies: - -```bash -composer require dragon-code/laravel-deploy-operations -``` - -If necessary, you can publish the configuration file by calling the console command: - -```bash -php artisan vendor:publish --tag=config --provider="DragonCode\LaravelDeployOperations\ServiceProvider" -``` - -## Publish the operation stub (optional) - -You may publish the stub used by the `make:operation` command and/or [Laravel Idea](https://laravel-idea.com) -plugin for [JetBrains PhpStorm](https://www.jetbrains.com/phpstorm/) if you want to modify it. - -```bash -php artisan vendor:publish --tag=stubs --provider="DragonCode\LaravelDeployOperations\ServiceProvider" -``` - -As a result, the file `stubs/deploy-operation.stub` will be created in the root of the project, -which you can change for yourself. diff --git a/docs/guide/basic.md b/docs/guide/basic.md deleted file mode 100644 index ce17d58e..00000000 --- a/docs/guide/basic.md +++ /dev/null @@ -1,66 +0,0 @@ -# Basic Usage - -Create your first operation using `make:operation` command and define the actions it should perform. - -```bash -php artisan make:operation -``` - -This action will create a new file in the `/operations` folder of your application. - -If you are using the `git` version control system, the name of the currently active branch will be used -as the file name suffix, otherwise the word `auto` will be used. - -You can also specify a name for the file yourself by specifying it with the first argument. -For example, `php artisan make:operation qwerty`. - -```php -use App\Models\Article; -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation { - public function __invoke(): void - { - Article::query() - ->lazyById(chunkSize: 100, column: 'id') - ->each->update(['is_active' => true]); - - // and/or any actions... - } -}; -``` - -Next, To run operations, execute the `operations` artisan command: - -```bash -php artisan operations -``` - -The order in which operations are called is checked by file name in alphabetical order, -without taking into account directory names: - -```bash -# actual file names -2022_10_14_000001_test1 # 1 -2022_10_14_000004_test4 # 4 -bar/2022_10_14_000003_test3 # 3 -foo/2022_10_14_000002_test2 # 2 -``` - -```bash -# order of running operations at startup -2022_10_14_000001_test1 # 1 -foo/2022_10_14_000002_test2 # 2 -bar/2022_10_14_000003_test3 # 3 -2022_10_14_000004_test4 # 4 -``` - -In addition to other options described in the "Guide" section, you can divide the execution of operations into -"before" and "after" certain actions. -For example, before and after restarting the queues: - -```bash -php artisan operations --before -php artisan queue:restart -php artisan operations -``` diff --git a/docs/guide/creating.md b/docs/guide/creating.md deleted file mode 100644 index 2e2db63b..00000000 --- a/docs/guide/creating.md +++ /dev/null @@ -1,154 +0,0 @@ -# Creating Operations - -To create an operation use the `make:operation` artisan command: - -```bash -php artisan make:operation some_name -``` - -The new operation's file will be placed in your `operations` directory in the base path of your app. - -Each operation file name contains a timestamp, which allows Laravel to determine the order of the operations. - -## Asks For File Name - -> The question will not be asked when calling a console command passing the `--quiet` parameter. - -When calling the `operations` console command without passing a name in the `name` parameter, -you will be asked for a name for the file. - -```bash -$ php artisan make:operation - Creating an operation - - β”Œ What should the operation be named? ─────────────────────────┐ - β”‚ E.g. activate articles β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Press Enter to autodetect -``` - -You can enter your own or simply press `Enter` to continue. -In this case, automatic file name generation will be applied. - -## Automatically Generate A File Name - -If you do not specify the "name" attribute, then the file name will be generated automatically according to the rule: - -> git branch name ?: 'auto' - -```bash -php artisan make:operation - -### When the git repository is found (`base_path('.git')` directory is exists) and HEAD branch name is 'qwerty' -# 2022_10_11_225116_qwerty.php -# 2022_10_11_225118_qwerty.php -# 2022_10_11_225227_qwerty.php - -### When the git repository is not found (`base_path('.git')` directory doesn't exists). -# 2022_10_11_225116_auto.php -# 2022_10_11_225118_auto.php -# 2022_10_11_225227_auto.php -``` - -## Nested Files - -You can use nested paths to create operations: - -```bash -php artisan make:operation Foo/Bar/QweRty -php artisan make:operation Foo/Bar/QweRty.php - -php artisan make:operation Foo\Bar\QweRty -php artisan make:operation Foo\Bar\QweRty.php - -php artisan make:operation foo\bar\QweRty -php artisan make:operation foo\bar\QweRty.php -``` - -All of these commands will create a file called `operations/foo/bar/Y_m_d_His_qwe_rty.php`. - -For example: - -```bash -php artisan make:operation foo\bar\QweRty -# operations/foo/bar/2022_10_11_225734_qwe_rty.php - -php artisan make:operation foo\bar\QweRty.php -# operations/foo/bar/2022_10_11_225734_qwe_rty.php - -php artisan make:operation foo/bar/QweRty -# operations/foo/bar/2022_10_11_225734_qwe_rty.php - -php artisan make:operation foo/bar/QweRty.php -# operations/foo/bar/2022_10_11_225734_qwe_rty.php -``` - -## Invokable Method - -By default, the new operation class will contain the `__invoke` method, but you can easily replace it with public `up` -name. - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - public function __invoke(): void - { - // some code - } -}; -``` - -> Note that the `__invoke` method has been added as a single call. -> This means that when the operation is running, it will be called, but not when it is rolled back. -> -> You should also pay attention to the fact that if there is an `__invoke` method in the class, the `down` method will -> not be called. - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - public function __invoke(): void {} // called when `php artisan operations` running - - public function down(): void {} // doesn't call when `php artisan migrate:rollback` running - // and any other commands to revert the operation. -}; -``` - -## Dependency Injection - -You can also use the dependency injection with `__invoke`, `up` and `down` methods: - -```php -use DragonCode\LaravelDeployOperations\Operation; -use Tests\Concerns\Some; - -return new class extends Operation -{ - public function __invoke(Some $some): void - { - $value = $some->get('qwerty'); - } -}; -``` - -```php -use DragonCode\LaravelDeployOperations\Operation; -use Tests\Concerns\Some; - -return new class extends Operation -{ - public function up(Some $some): void - { - $value = $some->get('qwerty'); - } - - public function down(Some $some): void - { - $value = $some->get('qwerty'); - } -}; -``` diff --git a/docs/guide/customize-stub.md b/docs/guide/customize-stub.md deleted file mode 100644 index 3f6a984c..00000000 --- a/docs/guide/customize-stub.md +++ /dev/null @@ -1,11 +0,0 @@ -# Customize Stub - -You may publish the stub used by the `make:operation` command and/or [Laravel Idea](https://laravel-idea.com) -plugin for [JetBrains PhpStorm](https://www.jetbrains.com/phpstorm/) if you want to modify it. - -```bash -php artisan vendor:publish --tag=stubs --provider="DragonCode\LaravelDeployOperations\ServiceProvider" -``` - -As a result, the file `stubs/deploy-operation.stub` will be created in the root of the project, -which you can change for yourself. diff --git a/docs/guide/rollback.md b/docs/guide/rollback.md deleted file mode 100644 index d936f4fc..00000000 --- a/docs/guide/rollback.md +++ /dev/null @@ -1,71 +0,0 @@ -# Rolling Back Operations - -To roll back the latest operation, you may use the `rollback` command. This command rolls back the last "batch" of operations, which may include multiple operation files: - -``` -php artisan operations:rollback -``` - -You may roll back a limited number of operations by providing the `step` option to the rollback command. For example, the following command will roll back the last five operations: - -``` -php artisan operations:rollback --step=5 -``` - -The `operations:reset` command will roll back all of your application's operations: - -``` -php artisan operations:reset -``` - -For example: - -```bash -php artisan operations:rollback -# operation batch -# 2022_10_12_021837_some 1 -# 2022_10_12_021838_some 2 -# 2022_10_12_021839_some 2 -# 2022_10_12_021840_some 3 // will be canceled -# 2022_10_12_021841_some 3 // will be canceled - -php artisan operations:rollback --step=1 -# operation batch -# 2022_10_12_021837_some 1 -# 2022_10_12_021838_some 2 -# 2022_10_12_021839_some 2 -# 2022_10_12_021840_some 3 // will be canceled -# 2022_10_12_021841_some 3 // will be canceled - -php artisan operations:rollback --step=2 -# operation batch -# 2022_10_12_021837_some 1 -# 2022_10_12_021838_some 2 // will be canceled -# 2022_10_12_021839_some 2 // will be canceled -# 2022_10_12_021840_some 3 // will be canceled -# 2022_10_12_021841_some 3 // will be canceled -``` - -## Roll Back & Operation Using A Single Command - -The `operations:refresh` command will roll back all of your operations and then execute the `operations` command. This command effectively re-creates your entire -database: - -``` -php artisan operations:refresh -``` - -You may roll back & re-run a limited number of operations by providing the `step` option to the `refresh` command. For example, the following command will roll back & -re-run the last five operations: - -``` -php artisan operations:refresh --step=5 -``` - -## Drop All & Rerun Operations - -The `operations:fresh` command will drop all operation records from the operation table and then execute the operations command: - -``` -php artisan operations:fresh -``` diff --git a/docs/guide/running.md b/docs/guide/running.md deleted file mode 100644 index 3e17beeb..00000000 --- a/docs/guide/running.md +++ /dev/null @@ -1,288 +0,0 @@ -# Running Operations - -To run all of your outstanding operations, execute the `operations` artisan command: - -```bash -php artisan operations -``` - -The order in which operations are called is checked by file name in alphabetical order, -without taking into account directory names: - -```bash -# actual file names -2022_10_14_000001_test1 # 1 -2022_10_14_000004_test4 # 4 -bar/2022_10_14_000003_test3 # 3 -foo/2022_10_14_000002_test2 # 2 -``` - -```bash -# order of running operations at startup -2022_10_14_000001_test1 # 1 -foo/2022_10_14_000002_test2 # 2 -bar/2022_10_14_000003_test3 # 3 -2022_10_14_000004_test4 # 4 -``` - -## Isolating Operations Execution - -If you are deploying your application across multiple servers and running operations as part of your deployment process, -you likely do not want two servers attempting to run -the database at the same time. To avoid this, you may use the `isolated` option when invoking the `operations` command. - -When the `isolated` option is provided, Laravel will acquire an atomic lock using your application's cache driver before -attempting to run your operations. All other attempts to -run the `operations` command while that lock is held will not execute; however, the command will still exit with a -successful exit status code: - -```bash -php artisan operations --isolated -``` - -## Split Launch Option - -Sometimes it becomes necessary to launch operations separately, for example, to notify about the successful deployment -of a project. - -There is a `before` option for this when calling operations: - -```bash -php artisan operations --before -``` - -When calling the `operations` command with the `before` parameter, the script will execute only those operations within -which the value of the `before` parameter is `true`. - -For backwards compatibility, the `before` parameter is set to `true` by default, but operations will only be executed if -the option is explicitly passed. - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - protected bool $before = false; - - public function __invoke(): void - { - // some code - } -}; -``` - -For example, you need to call operations when deploying an application. Some operations should be run after the -operations are deployed, and others after the application is fully -launched. - -To run, you need to pass the `before` parameter. For example, when -using [`deployer`](https://github.com/deployphp/deployer) it would look like this: - -```php -task('deploy', [ - // ... - 'artisan:migrate', - 'artisan:operation --before', // here - 'deploy:publish', - 'php-fpm:reload', - 'artisan:queue:restart', - 'artisan:operations', // here -]); -``` - -Thus, when `operations` is called, all operations whose `before` parameter is `true` will be executed, and after that, -the remaining tasks will be executed. - -> Note: -> If you call the `operations` command without the `before` parameter, -> then all tasks will be executed regardless of the value of the `$before` -> attribute inside the operation class. - -## Forcing Operations To Run In Production - -> Some commands cannot be executed in production without confirmation. -> These include all commands except `operations:status` and `operations`. - -Some operations are destructive, which means they may cause you to lose data. In order to protect you from running these -commands against your production database, -you will be prompted for confirmation before the commands are executed. To force the commands to run without a prompt, -use the `--force` flag: - -```bash -php artisan operations:install --force -``` - -## Execution Every Time - -In some cases, you need to call the code every time you deploy the application. For example, to call reindexing. - -To do this, override the `$once` variable in the operation file: - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - protected bool $once = false; - - public function __invoke(): void - { - // some code - } -}; -``` - -If the value is `$once = false`, the `up` method will be called every time the `operations` command called. - -In this case, information about it will not be written to the `operations` table and, therefore, the `down` method will -not be called when the rollback command is called. - -> Note -> -> When using the `before` parameter to run command, it is recommended to override the value of the `$before` attribute -> to `false`, otherwise this operation will be executed twice. - -## Execution In A Specific Environment - -In some cases, it becomes necessary to execute an operation in a specific environment. For example `production`. - -For this you can use the `$environment` parameter: - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - protected string|array|null $environment = 'production'; - - public function __invoke(): void - { - // some code - } -}; -``` - -You can also specify multiple environment names: - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - protected string|array|null $environment = ['testing', 'staging']; - - public function __invoke(): void - { - // some code - } -}; -``` - -By default, the operation will run in all environments. The same will happen if you specify `null` or `[]` as the value. - -## Execution Excluding Certain Environments - -In some cases, it becomes necessary to execute an operation excluding certain environments. For example `production`. - -For this you can use the `$except_environment` parameter: - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - protected string|array|null $exceptEnvironment = 'production'; - - public function __invoke(): void - { - // some code - } -}; -``` - -You can also specify multiple environment names: - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - protected string|array|null $exceptEnvironment = ['testing', 'staging']; - - public function __invoke(): void - { - // some code - } -}; -``` - -By default, no operations will be excluded. The same happens if you specify `null` or `[]` value. - -## Database Transactions - -In some cases, it becomes necessary to undo previously performed operations in the database. For example, when code -execution throws an error. To do this, the code must be wrapped in -a transaction. - -By setting the `$transactions = true` parameter, you will ensure that your code is wrapped in a transaction without -having to manually call the `DB::transaction()` method. This -will reduce the time it takes to create the operation. - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - public function __invoke(): void - { - // some code - } - - public function hasTransactions(): bool - { - return true; - } - - public function transactionAttempts(): int - { - return 4; - } -}; -``` - -## Asynchronous Call - -In some cases, it becomes necessary to execute operations in an asynchronous manner without delaying the deployment -process. - -To do this, you need to override the `async` method in the operation class: - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - public function __invoke(): void - { - // some code - } - - public function isAsync(): bool - { - return true; - } -}; -``` - -In this case, the operation file that defines this parameter will run asynchronously using -the `DragonCode\LaravelDeployOperations\Jobs\OperationJob` class. - -The name of the connection and queue can be changed through -the [settings](https://github.com/TheDragonCode/laravel-deploy-operations/tree/main/config). - -::: Info -We remind you that in this case the [queuing system](https://laravel.com/docs/queues) must work in your application. - -Using Laravel version 8.37 and above, checking for the [uniqueness](https://laravel.com/docs/10.x/queues#unique-jobs) of -the execution is supported. -::: diff --git a/docs/guide/status.md b/docs/guide/status.md deleted file mode 100644 index 19e19080..00000000 --- a/docs/guide/status.md +++ /dev/null @@ -1,8 +0,0 @@ -# Operations Status - -The `operations:status` command displays the execution status of operations. -In it you can see which operations were executed and which were not: - -``` -php artisan operations:status -``` diff --git a/docs/helpers/artisan.md b/docs/helpers/artisan.md deleted file mode 100644 index 344807fc..00000000 --- a/docs/helpers/artisan.md +++ /dev/null @@ -1,18 +0,0 @@ -# Artisan Command - -Quite often, when working with operations, it becomes necessary to run one or another console command, -and each time you have to write the following code: - -```php -use DragonCode\LaravelDeployOperations\Operation; - -return new class extends Operation -{ - public function __invoke(): void - { - $this->artisan('some_command', [ - // parameters - ]); - } -}; -``` diff --git a/docs/helpers/events.md b/docs/helpers/events.md deleted file mode 100644 index f4d84fce..00000000 --- a/docs/helpers/events.md +++ /dev/null @@ -1,54 +0,0 @@ -# Events - -You can also handle events when executing operations: - -```php -DragonCode\LaravelDeployOperations\Events\DeployOperationStarted::class -DragonCode\LaravelDeployOperations\Events\DeployOperationEnded::class -DragonCode\LaravelDeployOperations\Events\DeployOperationFailed::class -DragonCode\LaravelDeployOperations\Events\NoPendingDeployOperations::class -``` - -If there are no operation files to execute, the `NoPendingDeployOperations` event will be sent. - -In other cases, the `DeployOperationStarted` event will be sent before processing starts, -and the `DeployOperationEnded` event will be sent after processing. - -For example: - -```php -namespace App\Providers; - -use App\Listeners\SomeOperationsListener; -use DragonCode\LaravelDeployOperations\Events\DeployOperationEnded; -use DragonCode\LaravelDeployOperations\Events\DeployOperationFailed; -use DragonCode\LaravelDeployOperations\Events\DeployOperationStarted; -use DragonCode\LaravelDeployOperations\Events\NoPendingDeployOperations; -use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; - -class EventServiceProvider extends ServiceProvider -{ - protected $listen = [ - DeployOperationStarted::class => [SomeOperationsListener::class], - DeployOperationEnded::class => [SomeOperationsListener::class], - DeployOperationFailed::class => [SomeOperationsListener::class], - NoPendingDeployOperations::class => [SomeOperationsListener::class], - ]; -} -``` - -```php -namespace App\Listeners; - -use DragonCode\LaravelDeployOperations\Enums\MethodEnum; -use DragonCode\LaravelDeployOperations\Events\BaseEvent; - -class SomeOperationsListener -{ - public function handle(BaseEvent $event): void - { - $method = $event->method; // MethodEnum object value - $isBefore = $event->before; // boolean - } -} -``` diff --git a/docs/helpers/execution-status.md b/docs/helpers/execution-status.md deleted file mode 100644 index 40c19320..00000000 --- a/docs/helpers/execution-status.md +++ /dev/null @@ -1,100 +0,0 @@ -# Execution Status - -You can also override the `success` and `failed` methods, which are called on success or failure processing. - -## If Success - -```php -use DragonCode\LaravelDeployOperations\Operation; -use Illuminate\Support\Facade\Log; - -return new class extends Operation -{ - public function up(): void - { - // - } - - public function down(): void - { - // - } - - public function success(): void - { - Log::info('success'); - } - - public function failed(): void - { - Log::info('failed'); - } -}; -``` - -Call the `php artisan operations` command. - -The log file will contain two `success` entries. - -## If Failed - -```php -use DragonCode\LaravelDeployOperations\Operation; -use Exeption; -use Illuminate\Support\Facade\Log; - -return new class extends Operation -{ - public function up(): void - { - throw new Exeption(); - } - - public function down(): void - { - throw new Exeption(); - } - - public function success(): void - { - Log::info('success'); - } - - public function failed(): void - { - Log::info('failed'); - } -}; -``` - -Call the `php artisan operations` command. - -The log file will contain two `failed` entries. - -## Invokable - -The methods will work in the same way in conjunction with the `__invoke` magic method. -The only difference is that in this case the `down` method will not be executed. - -```php -use DragonCode\LaravelDeployOperations\Operation; -use Illuminate\Support\Facade\Log; - -return new class extends Operation -{ - public function __invoke(): void - { - // - } - - public function success(): void - { - Log::info('success'); - } - - public function failed(): void - { - Log::info('failed'); - } -}; -``` diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 5f73a510..00000000 --- a/docs/index.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: 'Introduction' ---- -# πŸš€ Laravel Deploy Operations - -![the dragon code laravel deploy operations](https://preview.dragon-code.pro/the-dragon-code/deploy-operations.svg?brand=laravel&mode=dark) - -[![Stable Version][badge_stable]][link_packagist] -[![Total Downloads][badge_downloads]][link_packagist] -[![Github Workflow Status][badge_build]][link_build] -[![License][badge_license]][link_license] - -⚑ **Performing any actions during the deployment process** - -Create specific classes for a one-time or more-time usage, that can be executed automatically after each deployment. -Perfect for seeding or updating some data instantly after some database changes, feature updates, or perform any -actions. - -This package is for you if... - -- you regularly need to update specific data after you deploy new code -- you often perform jobs after deployment -- you sometimes forget to execute that one specific job and stuff gets crazy -- your code gets cluttered with jobs that are not being used anymore -- your co-workers always need to be reminded to execute that one job after some database changes -- you often seed or process data in a migration file (which is a big no-no!) - -[badge_build]: https://img.shields.io/github/actions/workflow/status/TheDragonCode/laravel-actions/phpunit.yml?style=flat-square - -[badge_downloads]: https://img.shields.io/packagist/dt/dragon-code/laravel-actions.svg?style=flat-square - -[badge_license]: https://img.shields.io/packagist/l/dragon-code/laravel-deploy-operations.svg?style=flat-square - -[badge_stable]: https://img.shields.io/github/v/release/TheDragonCode/laravel-actions?label=packagist&style=flat-square - -[link_build]: https://github.com/TheDragonCode/laravel-actions/actions - -[link_license]: license.md - -[link_packagist]: https://packagist.org/packages/dragon-code/laravel-deploy-operations - -[link_website]: https://deploy-operations.dragon-code.pro diff --git a/docs/upgrade-guide/3.x.md b/docs/upgrade-guide/3.x.md deleted file mode 100644 index 64bf0c76..00000000 --- a/docs/upgrade-guide/3.x.md +++ /dev/null @@ -1,125 +0,0 @@ -# Upgrading To 3.x from 2.x - -### High Impact Changes - -- [Change the location of the configuration file](#configuration) -- [Replacing named classes with anonymous ones](#anonymous-classes) -- [Changing the namespace of the parent class](#parent-namespace) -- [Changing variable names from `snake_case` to `camelCase` and added typing](#changed-properties) -- [Added recursive search for actions in a folder](#added-recursive-search-for-actions-in-a-folder) -- [PHP 7.3 and 7.4 was dropped](#php-802-required) -- Laravel 6.0 was dropped -- Dragon Code: Contracts (`dragon-code/contracts`) was dropped - -### Medium Impact Changes - -- [Changing the name of an action column in the database](#changed-action-repository) -- [Action storage directory changed](#actions-location) - -## The easiest way to upgrade - -> Note -> If you used inheritance of actions from other actions, then you will need to process these files manually. - -For your convenience, we have created an upgrade console command: - -```bash -composer require dragon-code/laravel-migration-actions:^3.0 -php artisan migrate:actions:upgrade -php artisan migrate -``` - -It will do the following: - -- Change the namespace of the abstract class -- Add a strict type declaration -- Replace the `up` method with `__invoke` if the class does not have a `down` method -- Replace named classes with anonymous ones -- Create a configuration file according to the data saved in your project -- Changes properties from `snake_case` to `camelCase` - -## Updating Dependencies - -### PHP 8.0.2 Required - -Deploy Actions for Laravel now requires PHP 8.0.2 or greater. - -### Composer Dependencies - -You should update the following dependency in your application's `composer.json` file: - -- `dragon-code/laravel-migration-actions` to `^3.0` - -## Configuration - -Publish the config file and migrate the settings from the `config/database.php` file to `config/actions.php`. - -```bash -php artisan vendor:publish --provider="DragonCode\LaravelActions\ServiceProvider" -``` - -## Actions Location - -Move the action files to the `actions` folder in the project root, or update the `actions.path` option in the -configuration file. - -## Parent Namespace - -Replace `DragonCode\LaravelActions\Support\Actionable` with `DragonCode\LaravelActions\Action`. - -## Anonymous Classes - -Replace named calls to your application's classes with anonymous ones. - -For example: - -```php -// before -use DragonCode\LaravelActions\Support\Actionable; - -class Some extends Actionable {} - -// after -use DragonCode\LaravelActions\Action; - -return new class extends Action {}; -``` - -## Invokable Method - -If your class does not contain a `down` method, then you can replace the `up` method with `__invoke`. - -## Changed Action Repository - -Just call the `php artisan migrate` command to make changes to the action repository table. - -## Changed Properties - -Make sure all overridden properties are typed: - -| Old Name | New Name | -|---------------------------------|--------------------------------------------------| -| protected $once | protected bool $once | -| protected $transactions | protected bool $transactions | -| protected $transaction_attempts | protected int $transactionAttempts | -| protected $environment | protected string\|array\|null $environment | -| protected $except_environment | protected string\|array\|null $exceptEnvironment | -| protected $before | protected bool $before | - -## Added recursive search for actions in a folder - -### Before: - -```bash -2022_10_13_013321_test1 -2022_10_13_013326_test2 -bar/2022_10_13_013323_test3 # will not be called -``` - -### After: - -```bash -2022_10_13_013321_test1 -2022_10_13_013326_test2 -bar/2022_10_13_013323_test3 # will be called -``` diff --git a/docs/upgrade-guide/4.x.md b/docs/upgrade-guide/4.x.md deleted file mode 100644 index 760d09cd..00000000 --- a/docs/upgrade-guide/4.x.md +++ /dev/null @@ -1,99 +0,0 @@ -# Upgrading To 4.x from 3.x - -### High-Impact Changes - -- [Rename package name](#rename-package-name) -- [Changing the names of console commands](#changing-the-names-of-console-commands) - -### Medium Impact Changes - -- [`Names::MIGRATE` constant name changed](#names-migrate-constant-name-changed) - -### Low Impact Changes - -- [Changed the default name of the table for storing actions](#changed-the-default-name-of-the-table-for-storing-actions) - -## The easiest way to upgrade - -> Note -> If you used inheritance of actions from other actions, then you will need to process these files manually. - -For your convenience, we have created an `upgrade` console command: - -```bash -composer remove dragon-code/laravel-migration-actions -composer require dragon-code/laravel-actions:^4.0 -php artisan actions:upgrade -php artisan migrate -``` - -It will do the following: - -- Renaming manually invoked commands in a project to a new name - -## Updating Dependencies - -### Rename package name - -You should update the following dependency in your application's `composer.json` file: - -Replace: - -```json -{ - "require": { - "dragon-code/laravel-migration-actions": "^3.0" - } -} -``` - -with - -```json -{ - "require": { - "dragon-code/laravel-actions": "^4.0" - } -} -``` - -Then you need to update the dependencies: - -```bash -composer update -``` - -## Changing the names of console commands - -| Old Name | New Name | -|----------------------------------------|--------------------------------| -| `php artisan make:migration:action` | `php artisan make:action` | -| `php artisan migrate:actions` | `php artisan actions` | -| `php artisan migrate:actions:install` | `php artisan actions:install` | -| `php artisan migrate:actions:fresh` | `php artisan actions:fresh` | -| `php artisan migrate:actions:refresh` | `php artisan actions:refresh` | -| `php artisan migrate:actions:reset` | `php artisan actions:reset` | -| `php artisan migrate:actions:rollback` | `php artisan actions:rollback` | -| `php artisan migrate:actions:status` | `php artisan actions:status` | -| `php artisan migrate:actions:upgrade` | `php artisan actions:upgrade` | - -## `Names::MIGRATE` constant name changed - -Replace - -```php -DragonCode\LaravelActions\Constants\Names::MIGRATE -``` - -with - -```php -DragonCode\LaravelActions\Constants\Names::ACTIONS -``` - -## Changed the default name of the table for storing actions - -The new table name is `actions`. - -You can also specify any name in the -application [settings](https://github.com/TheDragonCode/laravel-actions/blob/main/config/actions.php). diff --git a/docs/upgrade-guide/5.x.md b/docs/upgrade-guide/5.x.md deleted file mode 100644 index 620878fe..00000000 --- a/docs/upgrade-guide/5.x.md +++ /dev/null @@ -1,35 +0,0 @@ -# Upgrading To 5.x from 4.x - -## High Impact Changes - -- [Updating Dependencies](#updating-dependencies) - -## Updating Dependencies - -### PHP 8.2.0 Required - -`Deploy Actions for Laravel` now requires PHP 8.2.0 or greater. - -### Laravel 10.0 Required - -`Deploy Actions` now requires Laravel 10.0 or greater. - -### Composer Dependencies - -You should update the following dependencies in your application's `composer.json` file: - -- `dragon-code/laravel-actions` to `^5.0` - -Then you need to update the dependencies: - -```bash -composer update -``` - -### Laravel 10 - -If you are using Laravel 10, then you need to install the dependency: - -```bash -composer require doctrine/dbal -``` diff --git a/docs/upgrade-guide/6.x.md b/docs/upgrade-guide/6.x.md deleted file mode 100644 index b75dd6e3..00000000 --- a/docs/upgrade-guide/6.x.md +++ /dev/null @@ -1,198 +0,0 @@ -# Upgrading To 6.x from 5.x - -## High-Impact Changes - -- [Updating Dependencies](#updating-dependencies) -- [Changed the namespace](#changed-the-namespace) -- [Changed the name of the main class](#changed-the-name-of-the-main-class) -- [Changed names of console commands](#changed-names-of-console-commands) -- [Changed event names](#changed-event-names) -- [Configuration file name changed](#configuration-file-name-changed) - -## Minor-Impact Changes - -- [Changed directory location](#changed-directory-location) -- [Database transactions](#database-transactions) -- [Removed `$async` property](#removed-async-property) -- [Removed `operations:stub` command](#removed-operationsstub-command) -- [Changed property typing for events](#changed-property-typing-for-events) - -## Low-Impact Changes - -- [Stub name changed](#stub-name-changed) - -## The easiest way to upgrade - -> Note -> If you used inheritance of actions from other actions, then you will need to process these files manually. - -For your convenience, we have created an `upgrade` console command: - -```bash -composer remove dragon-code/laravel-actions -composer require dragon-code/laravel-deploy-operations:^6.0 - -php artisan operations:upgrade -php artisan migrate -``` - -It will do the following: - -- Changing the old namespace of β€œactions” to a new one -- Moves files to a new location -- Updates the configuration file -- Rename the stub file (if published) - -Please note that the script allows you to automate most of the actions, but may not complete them completely. -Therefore, you will need to manually check the result of the upgrade by checking this guide. - -## Updating Dependencies - -You should change the package name in the `composer.json` file from `dragon-code/laravel-actions` -to `dragon-code/laravel-deploy-operations`, and also change its version to `^6.0`: - -```json lines -{ - "require": { - // ... - "dragon-code/laravel-deploy-operations": "^6.0" - } -} -``` - -Then you need to update the dependencies: - -```bash -composer update -``` - -## Changed the namespace - -The namespace has been changed from `DragonCode\LaravelActions` to `DragonCode\LaravelDeployOperations`. - -You need to replace it in all actions of your application, as well as when using [events](../helpers/events.md). - -## Changed the name of the main class - -You should replace `DragonCode\LaravelActions\Action` namespace with `DragonCode\LaravelDeployOperations\Operation`. - -## Changed names of console commands - -| New Name | Old Name | -|-----------------------|--------------------| -| `make:operation` | `make:action` | -| `operations` | `actions` | -| `operations:fresh` | `actions:fresh` | -| `operations:install` | `actions:install` | -| `operations:refresh` | `actions:refresh` | -| `operations:reset` | `actions:reset` | -| `operations:rollback` | `actions:rollback` | -| `operations:status` | `actions:status` | -| `operations:stub` | `actions:stub` | -| `operations:upgrade` | `actions:upgrade` | - -## Changed event names - -| New Name | Old Name | -|-----------------------------|--------------------| -| `DeployOperationStarted` | `ActionStarted` | -| `DeployOperationEnded` | `ActionEnded` | -| `DeployOperationFailed` | `ActionFailed` | -| `NoPendingDeployOperations` | `NoPendingActions` | - -Don't forget to also change the namespace from `DragonCode\LaravelActions\Events` -to `DragonCode\LaravelDeployOperations\Events`. - -## Changed property typing for events - -The type of the `method` property for events has been changed. - -Before: - -```php -use DragonCode\LaravelActions\Events\ActionEnded; -use DragonCode\LaravelDeployOperations\Enums\MethodEnum; - -/** @var ActionEnded */ -$event->method; // is string -``` - -After: - -```php -use DragonCode\LaravelDeployOperations\Enums\MethodEnum; -use DragonCode\LaravelDeployOperations\Events\DeployOperationEnded; - -/** @var DeployOperationEnded */ -$event->method; // is MethodEnum -``` - -## Configuration file name changed - -We recommend that you delete the old configuration file `config/actions.php` and publish a new one. -This way you will see the changes made to it. - -```bash -php artisan vendor:publish --provider="DragonCode\LaravelDeployOperations\ServiceProvider" -``` - -## Changed names of constants - -If you use package constant references, you must also rename them. - -The old name was in `UPPER_CASE`, the new one was in `PascalCase`. - -For example: - -```php -// Old -class Names -{ - public const ACTIONS = 'actions'; - public const FRESH = 'actions:fresh'; - // ... -} -``` - -```php -// New -class Names -{ - public const Operations = 'operations'; - public const Fresh = 'operations:fresh'; - // ... -} -``` - -## Changed directory location - -File storage directory changed to `operations` from `actions`. - -## Database transactions - -The following properties have been removed: - -- `$transactions` -- `$transactionAttempts` - -Instead, you can use the `hasTransactions` and `transactionAttempts` methods. - -The `enabledTransactions` method has been renamed to `hasTransactions`. - -## Removed `$async` property - -The `$async` property has been removed from the base class. -You can use the previously available `isAsync` method instead. - -## Stub name changed - -If you published a stub file, then you also need to rename it from `stubs/action.stub` to `stubs/deploy-operation.stub` -and make changes to its structure. - -## Removed `operations:stub` command - -The `php artisan operations:stub` console command has been removed. Use another command instead: - -```bash -php artisan vendor:publish --tag=stubs --provider="DragonCode\LaravelDeployOperations\ServiceProvider" -``` diff --git a/docs/upgrade-guide/index.md b/docs/upgrade-guide/index.md deleted file mode 100644 index 024262d9..00000000 --- a/docs/upgrade-guide/index.md +++ /dev/null @@ -1,6 +0,0 @@ -# Upgrade Guide - -* [Upgrading To 6.x from 5.x](6.x.md) -* [Upgrading To 5.x from 4.x](5.x.md) -* [Upgrading To 4.x from 3.x](4.x.md) -* [Upgrading To 3.x from 2.x](3.x.md) diff --git a/package.json b/package.json deleted file mode 100644 index f0f5bb19..00000000 --- a/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "docs", - "version": "1.0.0", - "description": "Performing actions with saving the list of called files", - "author": "Andrey Helldar ", - "license": "MIT", - "homepage": "https://github.com/TheDragonCode/laravel-actions", - "bugs": { - "url": "https://github.com/TheDragonCode/laravel-actions/issues" - }, - "scripts": { - "dev": "vuepress dev docs --debug", - "build": "vuepress build docs" - }, - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/TheDragonCode/laravel-actions.git" - }, - "devDependencies": { - "@vuepress/bundler-vite": "^2.0.0-rc.15", - "@vuepress/plugin-prismjs": "^2.0.0-rc.43", - "@vuepress/plugin-shiki": "^2.0.0-rc.0", - "@vuepress/theme-default": "^2.0.0-rc.43", - "@vueuse/core": "^7.7.1", - "dotenv": "^16.4.5", - "sass-embedded": "^1.78.0", - "vuepress": "^2.0.0-rc.15" - }, - "engines": { - "node": ">=22.8" - } -} From 82ec4b14efe92492b9cc9976fb887c85fee5d02d Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 03:22:32 +0300 Subject: [PATCH 02/12] Documentation has been moved --- .github/workflows/docs.yml | 124 +++++++++ docs/cfg/buildprofiles.xml | 46 ++++ docs/do.tree | 38 +++ docs/images/.gitkeep | 0 docs/redirection-rules.xml | 49 ++++ docs/snippets/actual_file_names.sh | 5 + docs/snippets/ask.sh | 7 + docs/snippets/async.php | 17 ++ docs/snippets/before_after.sh | 5 + docs/snippets/deployer.php | 13 + docs/snippets/di_invoke.php | 13 + docs/snippets/di_up_down.php | 18 ++ docs/snippets/empty.php | 12 + docs/snippets/event_service_provider.php | 22 ++ docs/snippets/events_list.php | 8 + docs/snippets/example.php | 16 ++ docs/snippets/example_artisan.php | 14 + docs/snippets/except_environment.php | 17 ++ docs/snippets/failed_status.php | 28 ++ docs/snippets/invokable_status.php | 23 ++ docs/snippets/invoke_and_down.php | 14 + docs/snippets/listen_events.php | 24 ++ docs/snippets/make_auto.sh | 11 + docs/snippets/need_before.php | 17 ++ docs/snippets/nested.sh | 8 + docs/snippets/nested_example.sh | 11 + docs/snippets/on_environment.php | 17 ++ docs/snippets/on_environments.php | 17 ++ docs/snippets/once_method.php | 17 ++ docs/snippets/order_running_operations.sh | 5 + docs/snippets/rollback.sh | 23 ++ docs/snippets/some_listener.php | 16 ++ docs/snippets/success_status.php | 28 ++ docs/snippets/within_transactions.php | 17 ++ docs/topics/artisan-commands.topic | 20 ++ docs/topics/creating-operations.topic | 112 ++++++++ docs/topics/customize-stub.topic | 34 +++ docs/topics/database-data-dumper.topic | 57 ++++ docs/topics/events.topic | 43 +++ docs/topics/execution-status.topic | 52 ++++ docs/topics/installation.topic | 41 +++ docs/topics/introduction.topic | 46 ++++ docs/topics/operations-status.topic | 23 ++ docs/topics/rolling-back-operations.topic | 83 ++++++ docs/topics/running-operations.topic | 213 +++++++++++++++ docs/topics/upgrade-3.topic | 195 ++++++++++++++ docs/topics/upgrade-4.topic | 157 +++++++++++ docs/topics/upgrade-5.topic | 64 +++++ docs/topics/upgrade-6.topic | 302 ++++++++++++++++++++++ docs/topics/upgrade-7.topic | 26 ++ docs/topics/usage.topic | 50 ++++ docs/v.list | 35 +++ docs/writerside.cfg | 10 + src/ServiceProvider.php | 4 +- 54 files changed, 2265 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/cfg/buildprofiles.xml create mode 100644 docs/do.tree create mode 100644 docs/images/.gitkeep create mode 100644 docs/redirection-rules.xml create mode 100644 docs/snippets/actual_file_names.sh create mode 100644 docs/snippets/ask.sh create mode 100644 docs/snippets/async.php create mode 100644 docs/snippets/before_after.sh create mode 100644 docs/snippets/deployer.php create mode 100644 docs/snippets/di_invoke.php create mode 100644 docs/snippets/di_up_down.php create mode 100644 docs/snippets/empty.php create mode 100644 docs/snippets/event_service_provider.php create mode 100644 docs/snippets/events_list.php create mode 100644 docs/snippets/example.php create mode 100644 docs/snippets/example_artisan.php create mode 100644 docs/snippets/except_environment.php create mode 100644 docs/snippets/failed_status.php create mode 100644 docs/snippets/invokable_status.php create mode 100644 docs/snippets/invoke_and_down.php create mode 100644 docs/snippets/listen_events.php create mode 100644 docs/snippets/make_auto.sh create mode 100644 docs/snippets/need_before.php create mode 100644 docs/snippets/nested.sh create mode 100644 docs/snippets/nested_example.sh create mode 100644 docs/snippets/on_environment.php create mode 100644 docs/snippets/on_environments.php create mode 100644 docs/snippets/once_method.php create mode 100644 docs/snippets/order_running_operations.sh create mode 100644 docs/snippets/rollback.sh create mode 100644 docs/snippets/some_listener.php create mode 100644 docs/snippets/success_status.php create mode 100644 docs/snippets/within_transactions.php create mode 100644 docs/topics/artisan-commands.topic create mode 100644 docs/topics/creating-operations.topic create mode 100644 docs/topics/customize-stub.topic create mode 100644 docs/topics/database-data-dumper.topic create mode 100644 docs/topics/events.topic create mode 100644 docs/topics/execution-status.topic create mode 100644 docs/topics/installation.topic create mode 100644 docs/topics/introduction.topic create mode 100644 docs/topics/operations-status.topic create mode 100644 docs/topics/rolling-back-operations.topic create mode 100644 docs/topics/running-operations.topic create mode 100644 docs/topics/upgrade-3.topic create mode 100644 docs/topics/upgrade-4.topic create mode 100644 docs/topics/upgrade-5.topic create mode 100644 docs/topics/upgrade-6.topic create mode 100644 docs/topics/upgrade-7.topic create mode 100644 docs/topics/usage.topic create mode 100644 docs/v.list create mode 100644 docs/writerside.cfg diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..04daf8be --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,124 @@ +name: Documentation + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + id-token: write + pages: write + +env: + COMPOSER_TOKEN: ${{ secrets.COMPOSER_TOKEN }} + ARTIFACT_DOCS: webHelpDO2-all.zip + INSTANCE: docs/do + DOMAIN_NAME: deploy-operations.dragon-code.pro + BUILDER_VERSION: 2025.03.8312 + +jobs: + build: + name: Build application + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build documentation + uses: JetBrains/writerside-github-action@v4 + with: + instance: ${{ env.INSTANCE }} + artifact: ${{ env.ARTIFACT_DOCS }} + docker-version: ${{ env.BUILDER_VERSION }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: docs + path: | + artifacts/${{ env.ARTIFACT_DOCS }} + artifacts/report.json + retention-days: 7 + + test: + needs: build + name: Testing + runs-on: ubuntu-latest + + steps: + - name: Download docs artifact + uses: actions/download-artifact@v4 + with: + name: docs + path: artifacts + + - name: Test documentation + uses: JetBrains/writerside-checker-action@v1 + with: + instance: ${{ env.INSTANCE }} + + robots: + needs: build + name: Generate robots.txt + runs-on: ubuntu-latest + + steps: + - name: Create robots.txt + run: | + touch robots.txt + echo "User-Agent: *" >> robots.txt + echo "Disallow: " >> robots.txt + echo "Host: https://${{ env.DOMAIN_NAME }}" >> robots.txt + echo "Sitemap: https://${{ env.DOMAIN_NAME }}/sitemap.xml" >> robots.txt + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: robots + path: robots.txt + retention-days: 7 + + deploy-pages: + environment: + name: deploy + url: ${{ steps.deployment.outputs.page_url }} + + needs: + - test + - robots + + name: Deploy to pages + runs-on: ubuntu-latest + + steps: + - name: Download docs artifact + uses: actions/download-artifact@v4 + with: + name: docs + + - name: Download robots artifact + uses: actions/download-artifact@v4 + with: + name: robots + + - name: Unzip artifact + run: unzip -O UTF-8 -qq '${{ env.ARTIFACT_DOCS }}' -d dir + + - name: Move robots + run: | + sudo mv robots.txt dir/robots.txt + + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: dir + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/docs/cfg/buildprofiles.xml b/docs/cfg/buildprofiles.xml new file mode 100644 index 00000000..38e424e3 --- /dev/null +++ b/docs/cfg/buildprofiles.xml @@ -0,0 +1,46 @@ + + + + + + true + en_US + + + + + https://deploy-operations.dragon-code.pro + true + + https://github.com/TheDragonCode/laravel-deploy-operations/edit/main/docs/ + + + + + + + + + + + https://deploy-operations.dragon-code.pro/ + false + + + + + + +
+ + GitHub + + + Boosty + + + Issues + +
+
diff --git a/docs/do.tree b/docs/do.tree new file mode 100644 index 00000000..5403f93d --- /dev/null +++ b/docs/do.tree @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/.gitkeep b/docs/images/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/redirection-rules.xml b/docs/redirection-rules.xml new file mode 100644 index 00000000..cc900128 --- /dev/null +++ b/docs/redirection-rules.xml @@ -0,0 +1,49 @@ + + + + + + Created after removal of "About Deploy Operations" from Deploy Operations + starter-topic.html + + + Created after removal of "Running Operations" from Deploy Operations + guide-running-operations.html + + + Created after removal of "Running operations" from Deploy Operations + running-operations.html + + + Created after removal of "Creation Operations" from Deploy Operations + creation-operations.html + + + Created after removal of "Operations Status" from Deploy Operations + operations-status.html + + + Created after removal of "Helpers" from Deploy Operations + Helpers.html + + + Created after removal of "Rolling Back Operations" from Deploy Operations + Rolling-Back-Operations.html + + + Created after removal of "Artisan Command" from Deploy Operations + artisan-command.html + + + Created after removal of "Events" from Deploy Operations + events.html + + + Created after removal of "Execution Status" from Deploy Operations + execution-status.html + + diff --git a/docs/snippets/actual_file_names.sh b/docs/snippets/actual_file_names.sh new file mode 100644 index 00000000..8b7bd726 --- /dev/null +++ b/docs/snippets/actual_file_names.sh @@ -0,0 +1,5 @@ +# actual file names +2022_10_14_000001_test1 # 1 +2022_10_14_000004_test4 # 4 +bar/2022_10_14_000003_test3 # 3 +foo/2022_10_14_000002_test2 # 2 diff --git a/docs/snippets/ask.sh b/docs/snippets/ask.sh new file mode 100644 index 00000000..93b4d7d5 --- /dev/null +++ b/docs/snippets/ask.sh @@ -0,0 +1,7 @@ +php artisan make:operation + Creating an operation + + β”Œ What should the operation be named? ─────────────────────────┐ + β”‚ E.g. activate articles β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + Press Enter to autodetect diff --git a/docs/snippets/async.php b/docs/snippets/async.php new file mode 100644 index 00000000..d88deb62 --- /dev/null +++ b/docs/snippets/async.php @@ -0,0 +1,17 @@ +get('qwerty'); + } +}; diff --git a/docs/snippets/di_up_down.php b/docs/snippets/di_up_down.php new file mode 100644 index 00000000..5d3a6fdf --- /dev/null +++ b/docs/snippets/di_up_down.php @@ -0,0 +1,18 @@ +get('qwerty'); + } + + public function down(Some $some): void + { + $value = $some->get('qwerty'); + } +}; diff --git a/docs/snippets/empty.php b/docs/snippets/empty.php new file mode 100644 index 00000000..e43e0bc3 --- /dev/null +++ b/docs/snippets/empty.php @@ -0,0 +1,12 @@ + [SomeOperationsListener::class], + DeployOperationEnded::class => [SomeOperationsListener::class], + DeployOperationFailed::class => [SomeOperationsListener::class], + NoPendingDeployOperations::class => [SomeOperationsListener::class], + ]; +} diff --git a/docs/snippets/events_list.php b/docs/snippets/events_list.php new file mode 100644 index 00000000..64380926 --- /dev/null +++ b/docs/snippets/events_list.php @@ -0,0 +1,8 @@ +lazyById(chunkSize: 100, column: 'id') + ->each->update(['is_active' => true]); + // and/or any actions... + } +}; diff --git a/docs/snippets/example_artisan.php b/docs/snippets/example_artisan.php new file mode 100644 index 00000000..42dce587 --- /dev/null +++ b/docs/snippets/example_artisan.php @@ -0,0 +1,14 @@ +artisan('some_command', [ + // parameters + ]); + } +}; diff --git a/docs/snippets/except_environment.php b/docs/snippets/except_environment.php new file mode 100644 index 00000000..1a2adbb9 --- /dev/null +++ b/docs/snippets/except_environment.php @@ -0,0 +1,17 @@ +environment(), ['testing', 'staging'], true); + } +}; diff --git a/docs/snippets/failed_status.php b/docs/snippets/failed_status.php new file mode 100644 index 00000000..97e15152 --- /dev/null +++ b/docs/snippets/failed_status.php @@ -0,0 +1,28 @@ +isProduction(); + } +}; diff --git a/docs/snippets/on_environments.php b/docs/snippets/on_environments.php new file mode 100644 index 00000000..e9bb593d --- /dev/null +++ b/docs/snippets/on_environments.php @@ -0,0 +1,17 @@ +environment(), ['testing', 'staging'], true); + } +}; diff --git a/docs/snippets/once_method.php b/docs/snippets/once_method.php new file mode 100644 index 00000000..0d8ece1c --- /dev/null +++ b/docs/snippets/once_method.php @@ -0,0 +1,17 @@ +method; // MethodEnum object value + $isBefore = $event->before; // boolean + } +} diff --git a/docs/snippets/success_status.php b/docs/snippets/success_status.php new file mode 100644 index 00000000..c5838192 --- /dev/null +++ b/docs/snippets/success_status.php @@ -0,0 +1,28 @@ + + + + + Information on how to call Artisan commands from operations + Information on how to call Artisan commands from operations + Information on how to call Artisan commands from operations + + + +

+ Quite often, when working with operations, it becomes necessary to run one or another console command, and each time you have to write the following code: +

+ + +
diff --git a/docs/topics/creating-operations.topic b/docs/topics/creating-operations.topic new file mode 100644 index 00000000..eb098bac --- /dev/null +++ b/docs/topics/creating-operations.topic @@ -0,0 +1,112 @@ + + + + + Information on how to create operations + Information on how to create operations + Information on how to create operations + + + +

+ To create an operation use the %command_make% artisan command: +

+ + + %artisan% %command_make% some_name + + +

+ The new operation's file will be placed in your %directory% directory in the base path of your app. +

+ +

+ Each operation file name contains a timestamp, which allows Laravel to determine the order of the operations. +

+ + + + The question will not be asked when calling a console command passing the --quiet parameter. + + +

+ When calling the %command_run% console command without passing a name in the name parameter, + you will be asked for a name for the file. +

+ + + +

+ You can enter your own or simply press Enter to continue. + In this case, automatic file name generation will be applied +

+
+ + +

+ If you do not specify the name attribute, + then the file name will be generated automatically according to the rule: +

+ + + git branch name ?: 'auto' + + + +
+ + +

+ You can use nested paths to create operations: +

+ + + +

+ All of these commands will create a file called %directory%/foo/bar/Y_m_d_His_qwe_rty.php. +

+ +

+ For example: +

+ + +
+ + +

+ By default, the new operation class will contain the __invoke method, + but you can easily replace it with public up name. +

+ + + + +

+ Note that the __invoke method has been added as a single call. + This means that when the operation is running, it will be called, but not when it is rolled back. +

+ +

+ You should also pay attention to the fact that if there is an __invoke method in the class, + the down method will not be called. +

+
+ + +
+ + +

+ You can also use the dependency injection with __invoke, up and + down methods: +

+ + + +
+
diff --git a/docs/topics/customize-stub.topic b/docs/topics/customize-stub.topic new file mode 100644 index 00000000..8434d361 --- /dev/null +++ b/docs/topics/customize-stub.topic @@ -0,0 +1,34 @@ + + + + + Information on how to publish a template file for changes + Information on how to publish a template file for changes + Information on how to publish a template file for changes + + + +

+ You may publish the stub used by the make:operation command and/or + Laravel Idea plugin for + JetBrains PhpStorm if you want to modify it. +

+ + + %publish_files% + + +

+ As a result, the file stubs/deploy-operation.stub will be created in the root of the project, + which you can change for yourself. +

+ + +
diff --git a/docs/topics/database-data-dumper.topic b/docs/topics/database-data-dumper.topic new file mode 100644 index 00000000..536be7c2 --- /dev/null +++ b/docs/topics/database-data-dumper.topic @@ -0,0 +1,57 @@ + + + + + Adding data from certain tables when executing the `php artisan schema:dump` console command + Adding data from certain tables when executing the `php artisan schema:dump` console command + Adding data from certain tables when executing the `php artisan schema:dump` console command + + + +

+ As you build your application, you may accumulate more and more migrations over time. + This can lead to your + database/migrations directory becoming bloated with potentially hundreds of migrations. + If you would like, you may "squash" your migrations into a single SQL file. + To get started, execute the schema:dump command: +

+ + + %artisan% schema:dump + + +

+ You can read more about the operation of this console command in the + Laravel documentation. +

+ +

+ Here we mention this console command because operations tend to save the execution state in order to prevent re-runs where this is not explicitly allowed. + But if you run sequentially the console commands %artisan% schema:dump and + %artisan% migrate:fresh, you will see that all actions will be called again. +

+ +

+ This is due to the fact that the dump mechanism saves the contents of just one table - migrations. +

+ +

+ To solve this problem, there is a + Database Data Dumper + project that allows you to specify a list of tables required for export to a dump. +

+ +

+ In addition to those that you can easily specify in its configuration file, + we recommend that you also specify the + operations database table from this project in order to save the state of the operations when performing a clean deployment of the database from a dump. +

+ + + composer require dragon-code/laravel-data-dumper --dev + +
diff --git a/docs/topics/events.topic b/docs/topics/events.topic new file mode 100644 index 00000000..d810b47d --- /dev/null +++ b/docs/topics/events.topic @@ -0,0 +1,43 @@ + + + + + Information about events sent when operations are running + Information about events sent when operations are running + Information about events sent when operations are running + + + +

+ You can also handle events when executing operations: +

+ + + +

+ If there are no operation files to execute, the NoPendingDeployOperations event will be sent. +

+ +

+ In other cases, the DeployOperationStarted event will be sent before processing starts, + and the DeployOperationEnded event will be sent after processing. +

+ +

+ For example: +

+ + + + + +

+ It is also possible to subscribe to events manually: +

+ + +
diff --git a/docs/topics/execution-status.topic b/docs/topics/execution-status.topic new file mode 100644 index 00000000..c7ef5f41 --- /dev/null +++ b/docs/topics/execution-status.topic @@ -0,0 +1,52 @@ + + + + + Information about the execution of actions during successful and unsuccessful operation launches + Information about the execution of actions during successful and unsuccessful operation launches + Information about the execution of actions during successful and unsuccessful operation launches + + + +

+ You can also override the success and failed methods, + which are called on success or failure processing. +

+ + + + +

+ Call the %artisan% %command_run% command. +

+ +

+ The log file will contain one success record. +

+
+ + + + +

+ Call the %artisan% %command_run% command. +

+ +

+ The log file will contain one failed record. +

+
+ + +

+ The methods will work in the same way in conjunction with the __invoke magic method. + The only difference is that in this case the down method will not be executed. +

+ + +
+
diff --git a/docs/topics/installation.topic b/docs/topics/installation.topic new file mode 100644 index 00000000..1fc2c992 --- /dev/null +++ b/docs/topics/installation.topic @@ -0,0 +1,41 @@ + + + + + Installation and configuration + Installation and configuration + Installation and configuration + + + +

+ To get the latest version of + %product_short% + , simply require the project using + Composer: +

+ + + composer require %package_name% + + +

+ If necessary, you can publish the configuration file by calling the console command: +

+ + + %publish_files% + + +

+ Now you can + + create + + new operations. +

+
diff --git a/docs/topics/introduction.topic b/docs/topics/introduction.topic new file mode 100644 index 00000000..a5c4fe6b --- /dev/null +++ b/docs/topics/introduction.topic @@ -0,0 +1,46 @@ + + + + + + %product% + + + ⚑ Performing any actions during the deployment process + + + + + + + + + Guide + + + + + + + + + Helpers + + + + + + + + + Extras + + + + + + diff --git a/docs/topics/operations-status.topic b/docs/topics/operations-status.topic new file mode 100644 index 00000000..da5aa49a --- /dev/null +++ b/docs/topics/operations-status.topic @@ -0,0 +1,23 @@ + + + + + Information on how to view the status of performed operations + Information on how to view the status of performed operations + Information on how to view the status of performed operations + + + +

+ The %command_status% command displays the execution status of operations. + In it you can see which operations were executed and which were not: +

+ + + %artisan% %command_status% + +
diff --git a/docs/topics/rolling-back-operations.topic b/docs/topics/rolling-back-operations.topic new file mode 100644 index 00000000..11660384 --- /dev/null +++ b/docs/topics/rolling-back-operations.topic @@ -0,0 +1,83 @@ + + + + + Information on how to roll back operations + Information on how to roll back operations + Information on how to roll back operations + + + +

+ To roll back the latest operation, you may use the %command_rollback% command. + This command rolls back the last "batch" of operations, which may include multiple operation files: +

+ + + %artisan% %command_rollback% + + +

+ You may roll back a limited number of operations by providing the + step option to the rollback command. + For example, the following command will roll back the last five operations: +

+ + + %artisan% %command_rollback% --step=5 + + +

+ The %command_reset% command will roll back all of your application's operations: +

+ + + %artisan% %command_reset% + + +

+ For example: +

+ + + + +

+ The + %command_refresh% command will roll back all of your operations and then execute the operations command. + This command effectively re-creates your entire database: +

+ + + %artisan% %command_refresh% + + +

+ You may roll back and re-run a limited number of operations by providing the step option to the + %command_refresh% command. + For example, the following command will roll back and re-run the last five operations: +

+ + + %artisan% %command_refresh% --step=5 + +
+ + +

+ The + %command_fresh% command will drop all operation records from the operation table and then execute the operations command: +

+ + + %artisan% %command_fresh% + +
+
diff --git a/docs/topics/running-operations.topic b/docs/topics/running-operations.topic new file mode 100644 index 00000000..ae3f23a4 --- /dev/null +++ b/docs/topics/running-operations.topic @@ -0,0 +1,213 @@ + + + + + Information on how to invoke operations during a deployment + Information on how to invoke operations during a deployment + Information on how to invoke operations during a deployment + + + + + +

+ To run all of your outstanding operations, execute the %command_run% artisan command: +

+ + + %artisan% %command_run% + + +

+ The order in which operations are called is checked by file name in alphabetical order, without taking into account directory names: +

+ + + +
+ + +

+ If you are deploying your application across multiple servers and running operations as part of your deployment process, + you likely do not want two servers attempting to run the database at the same time. + To avoid this, you may use the isolated option when invoking the + %command_run% command. +

+ + + %artisan% %command_run% --isolated + +
+ + +

+ Sometimes it becomes necessary to launch operations separately, for example, to notify about the successful deployment of a project. +

+ +

+ There is a before option for this when calling operations: +

+ + + %artisan% %command_run% --before + + +

+ When you call the %command_run% command with the before parameter, + the script will only perform operations for which the needBefore method is true. +

+ +

+ For backwards compatibility, the needBefore method returns true by default, + but operations will only be executed if the option is explicitly passed. +

+ + + +

+ For example, you need to call operations when deploying an application. Some operations should be run after the operations are deployed, and others after the application is fully launched. +

+ +

+ To run, you need to pass the before parameter. + For example, when using + Deployer it would look like this: +

+ + + +

+ Thus, when %command_run% is called, all operations whose + before parameter is true will be executed, + and after that, the remaining tasks will be executed. +

+ + + If you call the %command_run% command without the before parameter, + then all tasks will be executed regardless of the value of the + needBefore method inside the operation class. + + + + + + Some commands cannot be executed in production without confirmation. + These include all commands except %command_status% and %command_run%. + + +

+ Some operations are destructive, which means they may cause you to lose data. + In order to protect you from running these commands against your production database, + you will be prompted for confirmation before the commands are executed. + To force the commands to run without a prompt, use the --force flag: +

+ + + %artisan% %command_install% --force + +
+ + +

+ In some cases, you need to call the code every time you deploy the application. For example, to call reindexing. +

+ +

+ To do this, override the shouldOnce method in the operation file: +

+ + + +

+ If the value is shouldOnce is false, + the up method will be called every time the %command_run% command called. +

+ +

+ In this case, information about it will not be written to the + %table% table and, therefore, the + down method will not be called when the rollback command is called. +

+ + + When using the before parameter to run command, + it is recommended to override the value of the needBefore method to false, + otherwise this operation will be executed twice. + +
+ + + + By default, the operation will run in all environments. + + +

+ In some cases, it becomes necessary to execute an operation in a specific environment. + For example production. +

+ +

+ For this you can override the shouldRun method: +

+ + + +

+ You can also specify multiple environment names: +

+ + + +

+ You can work with exceptions in the same way: +

+ + +
+ + +

+ In some cases, it becomes necessary to undo previously performed operations in the database. + For example, when code execution throws an error. To do this, the code must be wrapped in a transaction. +

+ +

+ By setting the withinTransactions to true parameter, + you will ensure that your code is wrapped in a transaction without having to manually call the + DB::transaction() method. + This will reduce the time it takes to create the operation. +

+ + +
+ + +

+ In some cases, it becomes necessary to execute operations in an asynchronous manner without delaying the deployment process. +

+ +

+ To do this, you need to override the shouldBeAsync method in the operation class: +

+ + + +

+ In this case, the operation file that defines this parameter will run asynchronously using the + DragonCode\LaravelDeployOperations\Jobs\OperationJob class. +

+ +

+ The name of the connection and queue can be changed through the settings. +

+ + + We remind you that in this case the + queuing system must work in your application. + +
+ diff --git a/docs/topics/upgrade-3.topic b/docs/topics/upgrade-3.topic new file mode 100644 index 00000000..fd1ccff7 --- /dev/null +++ b/docs/topics/upgrade-3.topic @@ -0,0 +1,195 @@ + + + + + Guide for upgrading to version 3.x from 2.x + Guide for upgrading to version 3.x from 2.x + Guide for upgrading to version 3.x from 2.x + + + + + + + + + + + + Laravel 6.0 support was ended + Dragon Code: Contracts (dragon-code/contracts) support was ended + + + + + + + + + + If you used inheritance of actions from other actions, then you will need to process these files manually. + + +

+ For your convenience, we have created an upgrade console command: +

+ + + composer require dragon-code/laravel-migration-actions:^3.0 + %artisan% migrate:actions:upgrade + %artisan% migrate + + +

+ It will do the following: +

+ + +
  • Change the namespace of the abstract class
  • +
  • Add a strict type declaration
  • +
  • Replace the up method with __invoke if the class does not have a + down method +
  • +
  • Replace named classes with anonymous ones
  • +
  • Create a configuration file according to the data saved in your project
  • +
  • Changes properties from snake_case to camelCase
  • +
    +
    + + + +

    + Deploy Actions for Laravel now requires PHP 8.0.2 or greater. +

    +
    + + +

    + You should update the following dependency in your application's composer.json file: +

    + + + { + "require": { + "dragon-code/laravel-migration-actions": "^3.0" + } + } + +
    +
    + + +

    + Publish the config file and migrate the settings from the config/database.php file to + config/actions.php. +

    + + + %artisan% vendor:publish --provider="DragonCode\LaravelActions\ServiceProvider" + +
    + + + Move the action files to the actions folder in the project root, + or update the actions.path option in the configuration file. + + + + Replace DragonCode\LaravelActions\Support\Actionable with + DragonCode\LaravelActions\Action. + + + +

    + Replace named calls to your application's classes with anonymous ones. +

    + +

    + For example: +

    + + + // before + use DragonCode\LaravelActions\Support\Actionable; + + class Some extends Actionable { } + + // after + use DragonCode\LaravelActions\Action; + + return new class extends Action { }; + +
    + + + If your class does not contain a down method, then you can replace the up method with + __invoke. + + + + Just call the %artisan% migrate command to make changes to the action repository table. + + + +

    + Make sure all overridden properties are typed: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    New NameOld Name
    protected bool $onceprotected $once
    protected bool $transactionsprotected $transactions
    protected int $transactionAttemptsprotected $transaction_attempts
    protected string\|array\|null $environmentprotected $environment
    protected string\|array\|null $exceptEnvironmentprotected $except_environment
    protected bool $beforeprotected $before
    +
    + + +

    + Before: +

    + + + 2022_10_13_013321_test1 + 2022_10_13_013326_test2 + bar/2022_10_13_013323_test3 # will not be called + + +

    + After: +

    + + + 2022_10_13_013321_test1 + 2022_10_13_013326_test2 + bar/2022_10_13_013323_test3 # will be called + +
    +
    diff --git a/docs/topics/upgrade-4.topic b/docs/topics/upgrade-4.topic new file mode 100644 index 00000000..4c4bfc09 --- /dev/null +++ b/docs/topics/upgrade-4.topic @@ -0,0 +1,157 @@ + + + + + Guide for upgrading to version 4.x from 3.x + Guide for upgrading to version 4.x from 3.x + Guide for upgrading to version 4.x from 3.x + + + + + + + + + + + + + + + + + + + + If you used inheritance of actions from other actions, then you will need to process these files manually. + + +

    + For your convenience, we have created an `upgrade` console command: +

    + + + composer remove dragon-code/laravel-migration-actions + composer require dragon-code/laravel-actions:^4.0 + + %artisan% actions:upgrade + %artisan% migrate + + +

    + It will do the following: +

    + + +
  • Renaming manually invoked commands in a project to a new name
  • +
    +
    + + + +

    + You should update the following dependency in your application's composer.json file: +

    + +

    + Replace: +

    + + + { + "require": { + "dragon-code/laravel-migration-actions": "^3.0" + } + } + + +

    + with: +

    + + + { + "require": { + "dragon-code/laravel-actions": "^4.0" + } + } + + +

    + Then you need to update the dependencies: +

    + + + composer update + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    New NameOld Name
    %artisan% make:action%artisan% make:migration:action
    %artisan% actions%artisan% migrate:actions
    %artisan% actions:install%artisan% migrate:actions:install
    %artisan% actions:fresh%artisan% migrate:actions:fresh
    %artisan% actions:refresh%artisan% migrate:actions:refresh
    %artisan% actions:reset%artisan% migrate:actions:reset
    %artisan% actions:rollback%artisan% migrate:actions:rollback
    %artisan% actions:status%artisan% migrate:actions:status
    %artisan% actions:upgrade%artisan% migrate:actions:upgrade
    +
    + + + Replace DragonCode\LaravelActions\Constants\Names::MIGRATE + with DragonCode\LaravelActions\Constants\Names::ACTIONS + + + +

    + The new table name is `actions`. +

    + +

    + You can also specify any name in the application + settings file. +

    + + diff --git a/docs/topics/upgrade-5.topic b/docs/topics/upgrade-5.topic new file mode 100644 index 00000000..b2f1f443 --- /dev/null +++ b/docs/topics/upgrade-5.topic @@ -0,0 +1,64 @@ + + + + + Guide for upgrading to version 5.x from 4.x + Guide for upgrading to version 5.x from 4.x + Guide for upgrading to version 5.x from 4.x + + + + + + + + + + Deploy Actions + now requires PHP 8.2.0 or greater. + + + +

    + Deploy Actions + now requires Laravel 10.0 or greater. +

    + + +

    + If you are using Laravel 10, then you need to install the dependency: +

    + + + composer require doctrine/dbal + +
    +
    + + +

    + You should update the following dependencies in your application's composer.json file: +

    + + + { + "require": { + "dragon-code/laravel-actions": "^5.0" + } + } + + +

    + Then you need to update the dependencies: +

    + + + composer update + +
    +
    +
    diff --git a/docs/topics/upgrade-6.topic b/docs/topics/upgrade-6.topic new file mode 100644 index 00000000..2bacfbd8 --- /dev/null +++ b/docs/topics/upgrade-6.topic @@ -0,0 +1,302 @@ + + + + + Guide for upgrading to version 6.x from 5.x + Guide for upgrading to version 6.x from 5.x + Guide for upgrading to version 6.x from 5.x + + + + + + + + + + + + + + + + + + + + + + + + + + + If you used inheritance of actions from other actions, then you will need to process these files manually. + + +

    + For your convenience, we have created an operations:upgrade console command: +

    + + + composer remove dragon-code/laravel-actions + composer require dragon-code/laravel-deploy-operations:^6.0 + + %artisan% operations:upgrade + %artisan% migrate + + +

    + It will do the following: +

    + + +
  • Changing the old namespace of β€œactions” to a new one
  • +
  • Moves files to a new location
  • +
  • Updates the configuration file
  • +
  • Rename the stub file (if published)
  • +
    + +

    + Please note that the script allows you to automate most of the actions, but may not complete them completely. + Therefore, you will need to manually check the result of the upgrade by checking this guide. +

    +
    + + +

    + You should change the package name in the composer.json file from + dragon-code/laravel-actions to + dragon-code/laravel-deploy-operations, and also change its version to ^6.0: +

    + + + { + "require": { + "dragon-code/laravel-deploy-operations": "^6.0" + } + } + + +

    + Then you need to update the dependencies: +

    + + + composer update + +
    + + +

    + The namespace has been changed from DragonCode\LaravelActions to + DragonCode\LaravelDeployOperations. +

    + + You need to replace it in all actions of your application, as well as when using +
    . + + + + You should replace DragonCode\LaravelActions\Action namespace with + DragonCode\LaravelDeployOperations\Operation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    New NameOld Name
    make:operationmake:action
    operationsactions
    operations:freshactions:fresh
    operations:installactions:install
    operations:refreshactions:refresh
    operations:resetactions:reset
    operations:rollbackactions:rollback
    operations:statusactions:status
    operations:stubactions:stub
    operations:upgradeactions:upgrade
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    New NameOld Name
    DeployOperationStartedActionStarted
    DeployOperationEndedActionEnded
    DeployOperationFailedActionFailed
    NoPendingDeployOperationsNoPendingActions
    + +

    + Don't forget to also change the namespace from DragonCode\LaravelActions\Events to + DragonCode\LaravelDeployOperations\Events. +

    +
    + + +

    + The type of the method property for events has been changed. +

    + + + + use DragonCode\LaravelActions\Events\ActionEnded; + use DragonCode\LaravelDeployOperations\Enums\MethodEnum; + + /** @var ActionEnded */ + $event->method; // is string + + + + + + use DragonCode\LaravelDeployOperations\Enums\MethodEnum; + use DragonCode\LaravelDeployOperations\Events\DeployOperationEnded; + + /** @var DeployOperationEnded */ + $event->method; // is MethodEnum + + +
    + + +

    + We recommend that you delete the old configuration file + config/actions.php and publish a new one. + This way you will see the changes made to it. +

    + + + %artisan% vendor:publish --provider="DragonCode\LaravelDeployOperations\ServiceProvider" + +
    + + +

    + If you use package constant references, you must also rename them. +

    + +

    + The old name was in UPPER_CASE, the new one was in PascalCase. +

    + +

    + For example: +

    + + + // Old + class Names + { + public const ACTIONS = 'actions'; + public const FRESH = 'actions:fresh'; + // ... + } + + + // New + class Names + { + public const Fresh = 'operations:fresh'; + public const Operations = 'operations'; + // ... + } + +
    + + + File storage directory changed to /operations from /actions. + + + +

    + The following properties have been removed: +

    + + +
  • $transactions
  • +
  • $transactionAttempts
  • +
    + +

    + Instead, you can use the hasTransactions and transactionAttempts methods. +

    + +

    + The enabledTransactions method has been renamed to hasTransactions. +

    +
    + + + The $async property has been removed from the base class. + You can use the previously available isAsync method instead. + + + + If you published a stub file, then you also need to rename it from stubs/action.stub to + stubs/deploy-operation.stub and make changes to its structure. + + + +

    + The %artisan% operations:stub console command has been removed. Use another command instead: +

    + + + %artisan% vendor:publish --tag=stubs --provider="DragonCode\LaravelDeployOperations\ServiceProvider" + +
    + diff --git a/docs/topics/upgrade-7.topic b/docs/topics/upgrade-7.topic new file mode 100644 index 00000000..290f1da0 --- /dev/null +++ b/docs/topics/upgrade-7.topic @@ -0,0 +1,26 @@ + + + + + Guide for upgrading to version 7.x from 6.x + Guide for upgrading to version 7.x from 6.x + Guide for upgrading to version 7.x from 6.x + + + + +
    + + + + + + + + + + diff --git a/docs/topics/usage.topic b/docs/topics/usage.topic new file mode 100644 index 00000000..bc11bb5e --- /dev/null +++ b/docs/topics/usage.topic @@ -0,0 +1,50 @@ + + + + + Information on how to use %product_short% + Information on how to use %product_short% + Information on how to use %product_short% + + + +

    + Create your first operation using %command_make% command and define the actions it should perform. +

    + + + %artisan% %command_make% + + +

    + This action will create a new file in the %directory% folder of your application. +

    + +

    + If you are using the git version control system, + the name of the currently active branch will be used as the file name suffix, + otherwise the word auto will be used. +

    + +

    + You can also specify a name for the file yourself by specifying it with the first argument. + For example, %artisan% %command_make% qwerty. +

    + + + + + +

    + In addition to other options described in the + + Guide + section, you can divide the execution of operations into "before" and "after" certain actions. For example, before and after restarting the queues: +

    + + + diff --git a/docs/v.list b/docs/v.list new file mode 100644 index 00000000..67e88908 --- /dev/null +++ b/docs/v.list @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/writerside.cfg b/docs/writerside.cfg new file mode 100644 index 00000000..157e3eb4 --- /dev/null +++ b/docs/writerside.cfg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index f63c5839..d90c4447 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -65,7 +65,7 @@ protected function publishConfig(): void { $this->publishes([ __DIR__ . '/../config/deploy-operations.php' => $this->app->configPath('deploy-operations.php'), - ], 'config'); + ], ['config', 'deploy-operations']); } protected function publishStub(): void @@ -74,7 +74,7 @@ protected function publishStub(): void __DIR__ . '/../resources/stubs/deploy-operation.stub' => $this->app->basePath( 'stubs/deploy-operation.stub' ), - ], 'stubs'); + ], ['stubs', 'deploy-operations']); } protected function registerConfig(): void From d0f7399d5ce61f91e00f9a44490e34845938a10d Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 03:42:12 +0300 Subject: [PATCH 03/12] Added compatibility table --- docs/images/.gitkeep | 0 docs/images/badge-not-supported.svg | 1 + docs/images/badge-not-supported_dark.svg | 1 + docs/images/badge-supported.svg | 1 + docs/images/badge-supported_dark.svg | 1 + docs/images/logo.svg | 63 +++++++++++++++++++++++ docs/topics/installation.topic | 65 ++++++++++++++++++++++++ 7 files changed, 132 insertions(+) delete mode 100644 docs/images/.gitkeep create mode 100644 docs/images/badge-not-supported.svg create mode 100644 docs/images/badge-not-supported_dark.svg create mode 100644 docs/images/badge-supported.svg create mode 100644 docs/images/badge-supported_dark.svg create mode 100644 docs/images/logo.svg diff --git a/docs/images/.gitkeep b/docs/images/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/images/badge-not-supported.svg b/docs/images/badge-not-supported.svg new file mode 100644 index 00000000..cdd08a78 --- /dev/null +++ b/docs/images/badge-not-supported.svg @@ -0,0 +1 @@ +not supportednot supported \ No newline at end of file diff --git a/docs/images/badge-not-supported_dark.svg b/docs/images/badge-not-supported_dark.svg new file mode 100644 index 00000000..cdd08a78 --- /dev/null +++ b/docs/images/badge-not-supported_dark.svg @@ -0,0 +1 @@ +not supportednot supported \ No newline at end of file diff --git a/docs/images/badge-supported.svg b/docs/images/badge-supported.svg new file mode 100644 index 00000000..ba3771bb --- /dev/null +++ b/docs/images/badge-supported.svg @@ -0,0 +1 @@ +supportedsupported \ No newline at end of file diff --git a/docs/images/badge-supported_dark.svg b/docs/images/badge-supported_dark.svg new file mode 100644 index 00000000..ba3771bb --- /dev/null +++ b/docs/images/badge-supported_dark.svg @@ -0,0 +1 @@ +supportedsupported \ No newline at end of file diff --git a/docs/images/logo.svg b/docs/images/logo.svg new file mode 100644 index 00000000..96a5a57a --- /dev/null +++ b/docs/images/logo.svg @@ -0,0 +1,63 @@ + + + diff --git a/docs/topics/installation.topic b/docs/topics/installation.topic index 1fc2c992..74c2818a 100644 --- a/docs/topics/installation.topic +++ b/docs/topics/installation.topic @@ -38,4 +38,69 @@ new operations.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PHPLaravelPackageDocumentationStatus
    ^8.211, 12^7.0supported
    ^8.210, 11, 12^6.0Documentation + not supported
    ^8.210, 11^5.0Documentation + not supported
    ^8.07, 8, 9, 10, 11^4.0Documentation + not supported
    ^8.07, 8, 9^3.0Documentation + not supported
    ^7.3, ^8.06, 7, 8, 9^2.0---not supported
    ^7.3, ^8.06, 7, 8^1.0---not supported
    +
    From 6c83b7bc55f99aac866f2b914510afe6e5895a0c Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 03:42:21 +0300 Subject: [PATCH 04/12] Update title --- docs/do.tree | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/do.tree b/docs/do.tree index 5403f93d..5a62e325 100644 --- a/docs/do.tree +++ b/docs/do.tree @@ -3,7 +3,7 @@ SYSTEM "https://resources.jetbrains.com/writerside/1.0/product-profile.dtd"> From 098fd4e81efd2eb153576a903228fa3273a54cbf Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 03:42:35 +0300 Subject: [PATCH 05/12] Added logo --- docs/cfg/buildprofiles.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/cfg/buildprofiles.xml b/docs/cfg/buildprofiles.xml index 38e424e3..129966ce 100644 --- a/docs/cfg/buildprofiles.xml +++ b/docs/cfg/buildprofiles.xml @@ -6,7 +6,7 @@ true en_US - + logo.svg @@ -15,9 +15,9 @@ https://github.com/TheDragonCode/laravel-deploy-operations/edit/main/docs/ - - - + + logo.svg,logo.svg,logo.svg,logo.svg + From 308ec51725cc6f5964f55a18efd3d150fb53490b Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 03:42:44 +0300 Subject: [PATCH 06/12] Added version switcher --- .gitattributes | 1 - docs/cfg/buildprofiles.xml | 3 +++ docs/versions.json | 27 +++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 docs/versions.json diff --git a/.gitattributes b/.gitattributes index 2c7b640d..69458d0c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,5 +11,4 @@ tests/ export-ignore .gitattributes export-ignore .gitignore export-ignore -package.json export-ignore phpunit.xml export-ignore diff --git a/docs/cfg/buildprofiles.xml b/docs/cfg/buildprofiles.xml index 129966ce..ed702774 100644 --- a/docs/cfg/buildprofiles.xml +++ b/docs/cfg/buildprofiles.xml @@ -21,6 +21,9 @@ + + https://raw.githubusercontent.com/TheDragonCode/laravel-deploy-operations/refs/heads/main/docs/versions.json + diff --git a/docs/versions.json b/docs/versions.json new file mode 100644 index 00000000..a17d18f7 --- /dev/null +++ b/docs/versions.json @@ -0,0 +1,27 @@ +[ + { + "version": "7.x", + "url": "https://deploy-operations.dragon-code.pro", + "isCurrent": true + }, + { + "version": "6.x", + "url": "https://github.com/TheDragonCode/laravel-deploy-operations/tree/6.x/docs", + "isCurrent": false + }, + { + "version": "5.x", + "url": "https://github.com/TheDragonCode/laravel-deploy-operations/tree/5.x/docs", + "isCurrent": false + }, + { + "version": "4.x", + "url": "https://github.com/TheDragonCode/laravel-deploy-operations/tree/4.x/docs", + "isCurrent": false + }, + { + "version": "3.x", + "url": "https://github.com/TheDragonCode/laravel-deploy-operations/tree/3.x/docs", + "isCurrent": false + } +] From 73649505ce2d28c9a857ee69563122fae32f46bb Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 03:46:11 +0300 Subject: [PATCH 07/12] Fixed code-style --- docs/snippets/invokable_status.php | 2 +- docs/snippets/success_status.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/snippets/invokable_status.php b/docs/snippets/invokable_status.php index e1584baa..bbe2ea78 100644 --- a/docs/snippets/invokable_status.php +++ b/docs/snippets/invokable_status.php @@ -8,7 +8,7 @@ return new class extends Operation { public function __invoke(): void { - // + // some } public function success(): void diff --git a/docs/snippets/success_status.php b/docs/snippets/success_status.php index c5838192..7bd0618b 100644 --- a/docs/snippets/success_status.php +++ b/docs/snippets/success_status.php @@ -8,12 +8,12 @@ return new class extends Operation { public function up(): void { - // + // some } public function down(): void { - // + // some } public function success(): void From 37f597302ef7c5195fc9dc1aed9396faebba2714 Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 12:11:49 +0300 Subject: [PATCH 08/12] Updated icons --- docs/topics/introduction.topic | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/topics/introduction.topic b/docs/topics/introduction.topic index a5c4fe6b..66c3da1f 100644 --- a/docs/topics/introduction.topic +++ b/docs/topics/introduction.topic @@ -21,10 +21,10 @@ Guide - - - - + + + + From e7105f220494c947cc4a0d574453e1c4b93be071 Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 12:38:09 +0300 Subject: [PATCH 09/12] The description is actualized --- docs/snippets/operations_status.sh | 7 +++++ docs/topics/creating-operations.topic | 39 +++++++++++++++++--------- docs/topics/customize-stub.topic | 6 ++-- docs/topics/installation.topic | 2 +- docs/topics/operations-status.topic | 6 ++++ docs/topics/running-operations.topic | 22 +++++++++++---- docs/topics/usage.topic | 40 ++++----------------------- docs/v.list | 5 ++-- 8 files changed, 68 insertions(+), 59 deletions(-) create mode 100644 docs/snippets/operations_status.sh diff --git a/docs/snippets/operations_status.sh b/docs/snippets/operations_status.sh new file mode 100644 index 00000000..4a3e8a2d --- /dev/null +++ b/docs/snippets/operations_status.sh @@ -0,0 +1,7 @@ +2025_04_02_100000_some ............................................ [1] Ran +2025_04_02_100001_some ............................................ [1] Ran +2025_04_02_100002_some ............................................ [2] Ran +2025_04_02_100003_some............................................. [3] Ran +2025_04_02_100004_some............................................. [3] Ran +2025_04_02_100005_some............................................. Pending +2025_04_02_100006_some............................................. Pending diff --git a/docs/topics/creating-operations.topic b/docs/topics/creating-operations.topic index eb098bac..f1e563f4 100644 --- a/docs/topics/creating-operations.topic +++ b/docs/topics/creating-operations.topic @@ -12,21 +12,29 @@ -

    - To create an operation use the %command_make% artisan command: -

    + +

    + To create an operation use the %command_make% artisan command: +

    - + %artisan% %command_make% some_name -

    - The new operation's file will be placed in your %directory% directory in the base path of your app. -

    +

    + The new operation's file will be placed in your + %directory% directory in the base path of your app. +

    + +

    + Each operation file name contains a timestamp, which allows Laravel to determine the order of the operations. + For example, +

    -

    - Each operation file name contains a timestamp, which allows Laravel to determine the order of the operations. -

    + + 2025_04_02_121627_some_name.php + +
    @@ -52,11 +60,16 @@ then the file name will be generated automatically according to the rule:

    + + - git branch name ?: 'auto' +

    + The name for the file will be automatically obtained from the currently active git repository branch at the root of the project. +

    +

    + If the branch name cannot be determined, the word β€œauto” will be used. +

    - -
    diff --git a/docs/topics/customize-stub.topic b/docs/topics/customize-stub.topic index 8434d361..6e41e198 100644 --- a/docs/topics/customize-stub.topic +++ b/docs/topics/customize-stub.topic @@ -19,12 +19,12 @@

    - %publish_files% + %vendor_publish%

    - As a result, the file stubs/deploy-operation.stub will be created in the root of the project, - which you can change for yourself. + This will create the file stubs/deploy-operation.stub, which you can modify to suit you. +

    - %publish_files% + %vendor_publish%

    diff --git a/docs/topics/operations-status.topic b/docs/topics/operations-status.topic index da5aa49a..937ede4a 100644 --- a/docs/topics/operations-status.topic +++ b/docs/topics/operations-status.topic @@ -20,4 +20,10 @@ %artisan% %command_status% + +

    + For example, +

    + + diff --git a/docs/topics/running-operations.topic b/docs/topics/running-operations.topic index ae3f23a4..ddbef003 100644 --- a/docs/topics/running-operations.topic +++ b/docs/topics/running-operations.topic @@ -30,7 +30,7 @@ - +

    If you are deploying your application across multiple servers and running operations as part of your deployment process, you likely do not want two servers attempting to run the database at the same time. @@ -43,7 +43,7 @@ - +

    Sometimes it becomes necessary to launch operations separately, for example, to notify about the successful deployment of a project.

    @@ -93,7 +93,7 @@
    - + Some commands cannot be executed in production without confirmation. These include all commands except %command_status% and %command_run%. @@ -111,7 +111,7 @@
    - +

    In some cases, you need to call the code every time you deploy the application. For example, to call reindexing.

    @@ -140,7 +140,7 @@
    - + By default, the operation will run in all environments. @@ -183,6 +183,16 @@

    + + +

    + The number of code execution attempts in case of transaction errors is set in the + settings file. +

    +

    + By default, the number of attempts is %transactions_attempts%. +

    + @@ -198,7 +208,7 @@

    In this case, the operation file that defines this parameter will run asynchronously using the - DragonCode\LaravelDeployOperations\Jobs\OperationJob class. + DragonCode\LaravelDeployOperations\Jobs\OperationJob job.

    diff --git a/docs/topics/usage.topic b/docs/topics/usage.topic index bc11bb5e..e9b40ba8 100644 --- a/docs/topics/usage.topic +++ b/docs/topics/usage.topic @@ -12,39 +12,11 @@ -

    - Create your first operation using %command_make% command and define the actions it should perform. -

    + + + - - %artisan% %command_make% - - -

    - This action will create a new file in the %directory% folder of your application. -

    - -

    - If you are using the git version control system, - the name of the currently active branch will be used as the file name suffix, - otherwise the word auto will be used. -

    - -

    - You can also specify a name for the file yourself by specifying it with the first argument. - For example, %artisan% %command_make% qwerty. -

    - - - - - -

    - In addition to other options described in the - - Guide - section, you can divide the execution of operations into "before" and "after" certain actions. For example, before and after restarting the queues: -

    - - + + + diff --git a/docs/v.list b/docs/v.list index 67e88908..7d50fb15 100644 --- a/docs/v.list +++ b/docs/v.list @@ -17,11 +17,12 @@ - + - + + From 3eeea3f6056a4d0e80392621202d3d04f54e863c Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 13:24:47 +0300 Subject: [PATCH 10/12] Added upgrade guide for 7.x --- docs/docs_libraries.tree | 9 + docs/topics/snippets_composer.topic | 19 ++ docs/topics/upgrade-4.topic | 8 +- docs/topics/upgrade-5.topic | 8 +- docs/topics/upgrade-6.topic | 8 +- docs/topics/upgrade-7.topic | 267 +++++++++++++++++++++++++++- docs/writerside.cfg | 1 + 7 files changed, 296 insertions(+), 24 deletions(-) create mode 100644 docs/docs_libraries.tree create mode 100644 docs/topics/snippets_composer.topic diff --git a/docs/docs_libraries.tree b/docs/docs_libraries.tree new file mode 100644 index 00000000..74737f26 --- /dev/null +++ b/docs/docs_libraries.tree @@ -0,0 +1,9 @@ + + + + + + + diff --git a/docs/topics/snippets_composer.topic b/docs/topics/snippets_composer.topic new file mode 100644 index 00000000..809718b8 --- /dev/null +++ b/docs/topics/snippets_composer.topic @@ -0,0 +1,19 @@ + + + + + +

    + Then you need to update the dependencies: +

    + + + composer update + +
    +
    diff --git a/docs/topics/upgrade-4.topic b/docs/topics/upgrade-4.topic index 4c4bfc09..3031fc85 100644 --- a/docs/topics/upgrade-4.topic +++ b/docs/topics/upgrade-4.topic @@ -82,13 +82,7 @@ }
    -

    - Then you need to update the dependencies: -

    - - - composer update - +
    diff --git a/docs/topics/upgrade-5.topic b/docs/topics/upgrade-5.topic index b2f1f443..8bce803b 100644 --- a/docs/topics/upgrade-5.topic +++ b/docs/topics/upgrade-5.topic @@ -52,13 +52,7 @@ }
    -

    - Then you need to update the dependencies: -

    - - - composer update - + diff --git a/docs/topics/upgrade-6.topic b/docs/topics/upgrade-6.topic index 2bacfbd8..91e22f47 100644 --- a/docs/topics/upgrade-6.topic +++ b/docs/topics/upgrade-6.topic @@ -82,13 +82,7 @@ }
    -

    - Then you need to update the dependencies: -

    - - - composer update - + diff --git a/docs/topics/upgrade-7.topic b/docs/topics/upgrade-7.topic index 290f1da0..471f37e9 100644 --- a/docs/topics/upgrade-7.topic +++ b/docs/topics/upgrade-7.topic @@ -13,14 +13,275 @@ - + + + - + + - + + + + + + +

    + You should update the following dependencies in your application's composer.json file: +

    + + + { + "require": { + "dragon-code/laravel-deploy-operations": "^7.0" + } + } + + + +
    + + + Laravel 10 version is no longer supported due to the lack of event classes required for + %product_short% + . + + + + We decided to drop support for the php artisan operations:upgrade console command. + It does not exist now. + + + +

    + A strict typification has been added to all the project files. +

    + + + declare(strict_types=1); + +
    + + +

    + The DragonCode\LaravelDeployOperations\Helpers\ConfigHelper class has been removed and + DragonCode\LaravelDeployOperations\Data\Config\ConfigData, which is a Data object, is now used instead. +

    + +

    + For example, +

    + + + - $this->config->path('some'); // /operations/some + - config('deploy-operations.transactions.enabled'); // false + - config('deploy-operations.async'); // false + + + $this->config->path . 'some'; // /operations/some + + $this->config->transactions->enabled; // false + + $this->config->async; // false + +
    + + +

    + This tidied up the handling of settings and options. +

    +

    + If you used a direct reference to the Helpers/Config and + Values/Options classes, update your code. +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    New NameOld Name
    Commands\InstallCommandCommands\Install
    Commands\MakeCommandCommands\Make
    Commands\OperationsCommandCommands\Operations
    Commands\FreshCommandCommands\Fresh
    Commands\RefreshCommandCommands\Refresh
    Commands\ResetCommandCommands\Reset
    Commands\RollbackCommandCommands\Rollback
    Commands\StatusCommandCommands\Status
    Processors\FreshProcessorProcessors\Fresh
    Processors\InstallProcessorProcessors\Install
    Processors\MakeProcessorProcessors\Make
    Processors\OperationsProcessorProcessors\Operations
    Processors\RefreshProcessorProcessors\Refresh
    Processors\ResetProcessorProcessors\Reset
    Processors\RollbackProcessorProcessors\Rollback
    Processors\StatusProcessorProcessors\Status
    Helpers\GitHelperHelpers\Git
    Helpers\SorterHelperHelpers\Sorter
    Services\MigratorServiceServices\Migrator
    Services\MutexServiceServices\Mutex
    Values\OptionsDataValues\Options
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    New NameOld Name
    Concerns\HasAboutConcerns\About
    Concerns\HasArtisanConcerns\Artisan
    Concerns\HasIsolatableConcerns\Isolatable
    Concerns\HasOptionableConcerns\Optionable
    +
    + + +

    + The following properties and methods have been removed from the + DragonCode\LaravelDeployOperations\Operation + class: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    RemovedUse Instead
    protected bool $onceprotected bool shouldOnce(): bool
    protected array|string|null $environmentprotected bool shouldRun(): bool
    protected array|string|null $exceptEnvironmentprotected bool shouldRun(): bool
    protected bool $beforeprotected bool needBefore(): bool
    public function getConnection(): ?stringNot used
    public function isOnce(): boolprotected bool shouldOnce(): bool
    public function enabledTransactions(): boolpublic function withinTransactions(): bool
    public function transactionAttempts(): intIt is indicated in the settings
    public function onEnvironment(): arrayprotected bool shouldRun(): bool
    public function exceptEnvironment(): arrayprotected bool shouldRun(): bool
    public function allow(): boolprotected bool shouldRun(): bool
    public function hasBefore(): boolprotected bool needBefore(): bool
    public function isAsync(): boolprotected bool needAsync(): bool
    +
    diff --git a/docs/writerside.cfg b/docs/writerside.cfg index 157e3eb4..a24db4b0 100644 --- a/docs/writerside.cfg +++ b/docs/writerside.cfg @@ -7,4 +7,5 @@ + From 317335ca84c1659cdfbf5b9c64426546b267d9f0 Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 13:42:05 +0300 Subject: [PATCH 11/12] Added page for `OperationHelper` --- docs/do.tree | 1 + docs/snippets/operation_helper_all.php | 7 +++ docs/snippets/operation_helper_directory.php | 10 ++++ docs/snippets/operation_helper_file.php | 14 +++++ docs/snippets/operations_helper.sh | 5 ++ docs/topics/operation-helper.topic | 61 ++++++++++++++++++++ 6 files changed, 98 insertions(+) create mode 100644 docs/snippets/operation_helper_all.php create mode 100644 docs/snippets/operation_helper_directory.php create mode 100644 docs/snippets/operation_helper_file.php create mode 100644 docs/snippets/operations_helper.sh create mode 100644 docs/topics/operation-helper.topic diff --git a/docs/do.tree b/docs/do.tree index 5a62e325..62155acc 100644 --- a/docs/do.tree +++ b/docs/do.tree @@ -29,6 +29,7 @@ + diff --git a/docs/snippets/operation_helper_all.php b/docs/snippets/operation_helper_all.php new file mode 100644 index 00000000..4cb9239f --- /dev/null +++ b/docs/snippets/operation_helper_all.php @@ -0,0 +1,7 @@ + + + + + Information about launching operations with the help of the helper + Information about launching operations with the help of the helper + Information about launching operations with the help of the helper + + + +

    + To quickly call operations from other code, you can use the OperationHelper helper function. +

    + + +

    + This will execute any operations not performed earlier: +

    + + + +

    + For example, +

    + + +
    + + +

    + This will execute all previously unexecuted operations in the specified folder: +

    + + + +

    + For example, +

    + + +
    + + + + This will execute the defined operation file even if it was previously called. + Be careful about calling it again. + + + + +

    + For example, +

    + + +
    +
    From 83f65a4e249a11acba88f6c73ab8209619c5b9b8 Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 2 Apr 2025 13:54:01 +0300 Subject: [PATCH 12/12] Added `Interaction with migrations` section --- docs/snippets/with_operation.php | 17 +++++++++++ docs/topics/running-operations.topic | 43 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 docs/snippets/with_operation.php diff --git a/docs/snippets/with_operation.php b/docs/snippets/with_operation.php new file mode 100644 index 00000000..3e8de4b2 --- /dev/null +++ b/docs/snippets/with_operation.php @@ -0,0 +1,17 @@ +queuing system
    must work in your application.
    + + +

    + Operations can also be invoked when Laravel migrations are completed (php artisan migrate). + The Laravel event system is used for this purpose. +

    + +

    + To do this, add a withOperation public method to your migration file that + will return the name of the file or folder to call. + For example: +

    + + + +

    + Now, once the migration is done, Laravel will send a MigrationEnded event, catching which the + %artisan% %command_run% console command will be called passing this parameter. +

    + +

    + The same thing will happen if you invoke the following console command: +

    + + + %artisan% %command_run% --path="foo/2022_10_14_000002_test2" + + +

    + This method works with all three migration methods: up, down and + __invoke. +

    + +

    + When the %artisan% migrate console command is called, + the operation will call the up or __invoke method. +

    + +

    + When the %artisan% migrate:rollback console command is called, + the operation will call the down method if it exists in the operation file. +

    +