[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.md]\ntrim_trailing_whitespace = false\n\n[*.{yml,yaml}]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Path-based git attributes\n# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html\n\n# Ignore all test and documentation with \"export-ignore\".\n/.github            export-ignore\n/.gitattributes     export-ignore\n/.gitignore         export-ignore\n/phpunit.xml.dist   export-ignore\n/art                export-ignore\n/docs               export-ignore\n/tests              export-ignore\n/workbench          export-ignore\n/.editorconfig      export-ignore\n/.php_cs.dist.php   export-ignore\n/psalm.xml          export-ignore\n/psalm.xml.dist     export-ignore\n/testbench.yaml     export-ignore\n/UPGRADING.md       export-ignore\n/phpstan.neon.dist  export-ignore\n/phpstan-baseline.neon  export-ignore\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [salahhusa9]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\nlfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug.yml",
    "content": "name: Bug Report\ndescription: Report an Issue or Bug with the Package\ntitle: \"[Bug]: \"\nlabels: [\"bug\"]\nbody:\n    - type: markdown\n      attributes:\n          value: |\n              We're sorry to hear you have a problem. Can you help us solve it by providing the following details.\n    - type: textarea\n      id: what-happened\n      attributes:\n          label: What happened?\n          description: What did you expect to happen?\n          placeholder: I cannot currently do X thing because when I do, it breaks X thing.\n      validations:\n          required: true\n    - type: textarea\n      id: how-to-reproduce\n      attributes:\n          label: How to reproduce the bug\n          description: How did this occur, please add any config values used and provide a set of reliable steps if possible.\n          placeholder: When I do X I see Y.\n      validations:\n          required: true\n    - type: input\n      id: package-version\n      attributes:\n          label: Package Version\n          description: What version of our Package are you running? Please be as specific as possible\n          placeholder: 2.0.0\n      validations:\n          required: true\n    - type: input\n      id: php-version\n      attributes:\n          label: PHP Version\n          description: What version of PHP are you running? Please be as specific as possible\n          placeholder: 8.2.0\n      validations:\n          required: true\n    - type: input\n      id: laravel-version\n      attributes:\n        label: Laravel Version\n        description: What version of Laravel are you running? Please be as specific as possible\n        placeholder: 9.0.0\n      validations:\n        required: true\n    - type: dropdown\n      id: operating-systems\n      attributes:\n        label: Which operating systems does with happen with?\n        description: You may select more than one.\n        multiple: true\n        options:\n        - macOS\n        - Windows\n        - Linux\n    - type: textarea\n      id: notes\n      attributes:\n          label: Notes\n          description: Use this field to provide any other notes that you feel might be relevant to the issue.\n      validations:\n          required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Ask a question\n    url: https://github.com/salahhusa9/laravel-updater/discussions/new?category=q-a\n    about: Ask the community for help\n  - name: Request a feature\n    url: https://github.com/salahhusa9/laravel-updater/discussions/new?category=ideas\n    about: Share ideas for new features\n  - name: Report a security issue\n    url: https://github.com/salahhusa9/laravel-updater/security/policy\n    about: Learn how to notify us for sensitive bugs\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# Please see the documentation for all configuration options:\n# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    labels:\n      - \"dependencies\""
  },
  {
    "path": ".github/workflows/dependabot-auto-merge.yml",
    "content": "name: dependabot-auto-merge\non: pull_request_target\n\npermissions:\n  pull-requests: write\n  contents: write\n\njobs:\n  dependabot:\n    runs-on: ubuntu-latest\n    if: ${{ github.actor == 'dependabot[bot]' }}\n    steps:\n    \n      - name: Dependabot metadata\n        id: metadata\n        uses: dependabot/fetch-metadata@v2.5.0\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n          \n      - name: Auto-merge Dependabot PRs for semver-minor updates\n        if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}}\n        run: gh pr merge --auto --merge \"$PR_URL\"\n        env:\n          PR_URL: ${{github.event.pull_request.html_url}}\n          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}\n          \n      - name: Auto-merge Dependabot PRs for semver-patch updates\n        if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}}\n        run: gh pr merge --auto --merge \"$PR_URL\"\n        env:\n          PR_URL: ${{github.event.pull_request.html_url}}\n          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}\n"
  },
  {
    "path": ".github/workflows/deploy-docs.yml",
    "content": "# Sample workflow for building and deploying a Next.js site to GitHub Pages\n#\n# To get started with Next.js see: https://nextjs.org/docs/getting-started\n#\nname: Deploy Docs site to Pages\n\non:\n  # Runs on pushes targeting the default branch\n  push:\n    branches: [\"docs\"]\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\n# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.\n# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: false\n\njobs:\n  # Build job\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Detect package manager\n        id: detect-package-manager\n        run: |\n          if [ -f \"${{ github.workspace }}/yarn.lock\" ]; then\n            echo \"manager=yarn\" >> $GITHUB_OUTPUT\n            echo \"command=install\" >> $GITHUB_OUTPUT\n            echo \"runner=yarn\" >> $GITHUB_OUTPUT\n            exit 0\n          elif [ -f \"${{ github.workspace }}/package.json\" ]; then\n            echo \"manager=npm\" >> $GITHUB_OUTPUT\n            echo \"command=ci\" >> $GITHUB_OUTPUT\n            echo \"runner=npx --no-install\" >> $GITHUB_OUTPUT\n            exit 0\n          else\n            echo \"Unable to determine package manager\"\n            exit 1\n          fi\n      - name: Setup Node\n        uses: actions/setup-node@v6\n        with:\n          node-version: \"22\"\n          cache: ${{ steps.detect-package-manager.outputs.manager }}\n      # - name: Setup Pages\n      #   uses: actions/configure-pages@v3\n      #   with:\n      #     # Automatically inject basePath in your Next.js configuration file and disable\n      #     # server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized).\n      #     #\n      #     # You may remove this line if you want to manage the configuration yourself.\n      #     static_site_generator: next\n      - name: Restore cache\n        uses: actions/cache@v4\n        with:\n          path: |\n            .next/cache\n          # Generate a new cache whenever packages or source files change.\n          key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}\n          # If source files changed but packages didn't, rebuild from a prior cache.\n          restore-keys: |\n            ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-\n      - name: Install dependencies\n        run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}\n      - name: Build with Next.js\n        run: ${{ steps.detect-package-manager.outputs.runner }} next build\n      - name: Static HTML export with Next.js\n        run: ${{ steps.detect-package-manager.outputs.runner }} next export\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v4\n        with:\n          path: ./out\n\n  # Deployment job\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".github/workflows/fix-php-code-style-issues.yml",
    "content": "name: Fix PHP code style issues\n\non:\n  push:\n    paths:\n      - '**.php'\n\npermissions:\n  contents: write\n\njobs:\n  php-code-styling:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ github.head_ref }}\n\n      - name: Fix PHP code style issues\n        uses: aglipanci/laravel-pint-action@2.6\n\n      - name: Commit changes\n        uses: stefanzweifel/git-auto-commit-action@v7\n        with:\n          commit_message: Fix styling\n"
  },
  {
    "path": ".github/workflows/run-tests.yml",
    "content": "name: run-tests\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  test:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: true\n      matrix:\n        os: [ubuntu-latest, windows-latest]\n        # php: [8.1, 8.2]\n        laravel: [10.*, 11.*, 12.*]\n        stability: [prefer-lowest, prefer-stable]\n        include:\n          - laravel: 10.*\n            testbench: 8.*\n            php: 8.1\n          - laravel: 11.*\n            testbench: 9.*\n            php: 8.2\n          - laravel: 12.*\n            testbench: 10.*\n            php: 8.3\n\n    name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo\n          coverage: none\n\n      - name: Setup problem matchers\n        run: |\n          echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"\n          echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"\n\n      - name: Install dependencies\n        run: |\n          composer require \"laravel/framework:${{ matrix.laravel }}\" \"orchestra/testbench:${{ matrix.testbench }}\" --no-interaction --no-update\n          composer update --${{ matrix.stability }} --prefer-dist --no-interaction\n\n      - name: List Installed Dependencies\n        run: composer show -D\n\n      - name: Execute tests\n        run: vendor/bin/pest --ci\n"
  },
  {
    "path": ".github/workflows/update-changelog.yml",
    "content": "name: \"Update Changelog\"\n\non:\n  release:\n    types: [released]\n\npermissions:\n  contents: write\n\njobs:\n  update:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          ref: main\n\n      - name: Update Changelog\n        uses: stefanzweifel/changelog-updater-action@v1\n        with:\n          latest-version: ${{ github.event.release.name }}\n          release-notes: ${{ github.event.release.body }}\n\n      - name: Commit updated CHANGELOG\n        uses: stefanzweifel/git-auto-commit-action@v7\n        with:\n          branch: main\n          commit_message: Update CHANGELOG\n          file_pattern: CHANGELOG.md\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.phpunit.cache\nbuild\ncomposer.lock\ncoverage\ndocs\nphpunit.xml\nphpstan.neon\ntestbench.yaml\nvendor\nnode_modules\n\n.next\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to `laravel-updater` will be documented in this file.\n\n## v1.3.0 - 2025-04-01\n\n### What's Changed\n\n* Bump aglipanci/laravel-pint-action from 2.4 to 2.5 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/62\n* Update dependency illuminate/contracts to **v12** by @renovate in https://github.com/salahhusa9/laravel-updater/pull/63\n* Update dependency node to v22 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/65\n* chore(deps): update dependency orchestra/testbench to v10 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/64\n\n> Thank you for using this package! ❤️\nConsider supporting my work:\nhttps://github.com/sponsors/salahhusa9\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.4...v1.3.0\n\n## v1.2.4 - 2025-01-27\n\n### What's Changed\n\n* Update dependabot/fetch-metadata action to v2.3.0 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/58\n* Update Updater.php to merge before and after update pipelines with existing pipelines by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/60\n\nThank you for using this package! ❤️\nConsider supporting my work:\nhttps://github.com/sponsors/salahhusa9\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.3...v1.2.4\n\n## v1.2.3 - 2024-07-17\n\n### What's Changed\n\n* Update dependabot/fetch-metadata action to v2.2.0 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/52\n* [Add sponsor message and link in Update Command](https://github.com/sponsors/salahhusa9)\n\n> Thank you for using this package! ❤️\nConsider supporting my work:\nhttps://github.com/sponsors/salahhusa9\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.2...v1.2.3\n\n## v1.2.2 - 2024-06-25\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.1...v1.2.2\n\n## v1.2.1 - 2024-06-08\n\n### What's Changed\n\n* Update laravel in github action by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/44\n* Bump aglipanci/laravel-pint-action from 2.3.1 to 2.4 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/45\n* Update dependabot/fetch-metadata action to v2.1.0 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/46\n* Remove  symfony component process executable finder by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/50\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.0...v1.2.1\n\n## v1.2.0 - 2024-04-01\n\n### What's Changed\n\n* Git checkout throw away local modifications by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/43\n  \n* Update dependency orchestra/testbench to v9 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/39\n  \n* Update dependabot/fetch-metadata action to v1.7.0 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/40\n  \n* Update dependabot/fetch-metadata action to v2 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/41\n  \n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.1.0...v1.2.0\n\n## v1.1.0 - 2024-03-12\n\n### What's Changed\n\n* Add support of Laravel 11 by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/38\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.0.2...v1.1.0\n\n## v1.0.2 - 2024-02-10\n\n### What's Changed\n\n* new ui output by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/37\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.0.1...v1.0.2\n\n## v1.0.1 - 2024-02-03\n\n### What's Changed\n\n* Update actions/upload-pages-artifact action to v3 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/28\n* Update actions/deploy-pages action to v4 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/27\n* Bump aglipanci/laravel-pint-action from 2.3.0 to 2.3.1 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/30\n* remove migration file and in configure Package by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/36\n* Bump actions/cache from 3 to 4 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/32\n* [Update exception classes to use RuntimeException instead of Exception](https://github.com/salahhusa9/laravel-updater/commit/705485c97efaa161da81b3cc825e2b20c1f43d6f)\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.0.0...v1.0.1\n\n## Laravel Updater v1 - 2023-11-21\n\n### What's Changed\n\n- Update actions/setup-node action to v4 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/14\n- Git failed exception by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/17\n- Tests pipelines by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/18\n- Tests Repository Source by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/19\n- Command test by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/20\n- updater facade tests by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/21\n- Remove Git Pull in update by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/22\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v0.0.1...v1.0.0\n\n## Laravel Updater Beta - 2023-10-31\n\n### What's Changed\n\n- Bump aglipanci/laravel-pint-action from 2.2.0 to 2.3.0 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/1\n- Patch 1 by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/5\n- Pipelines by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/6\n- Configure Renovate by @renovate in https://github.com/salahhusa9/laravel-updater/pull/4\n- Bump stefanzweifel/git-auto-commit-action from 4 to 5 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/2\n- Bump actions/checkout from 3 to 4 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/3\n- Interface pipeline by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/10\n- Fun docs by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/11\n- Test by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/12\n- Output in run by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/13\n\n### New Contributors\n\n- @dependabot made their first contribution in https://github.com/salahhusa9/laravel-updater/pull/1\n- @salahhusa9 made their first contribution in https://github.com/salahhusa9/laravel-updater/pull/5\n- @renovate made their first contribution in https://github.com/salahhusa9/laravel-updater/pull/4\n\n**Full Changelog**: https://github.com/salahhusa9/laravel-updater/commits/v0.0.1\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) salahhusa9 <salahhusa9@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Laravel Updater\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/salahhusa9/laravel-updater.svg?style=flat-square)](https://packagist.org/packages/salahhusa9/laravel-updater)\n![laravel](https://img.shields.io/badge/Laravel-10%7C11%7C12-red)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/salahhusa9/laravel-updater/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/salahhusa9/laravel-updater/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/salahhusa9/laravel-updater/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/salahhusa9/laravel-updater/actions?query=workflow%3A\"Fix+PHP+code+style+issues\"+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/salahhusa9/laravel-updater.svg?style=flat-square)](https://packagist.org/packages/salahhusa9/laravel-updater)\n\nThis is a useful package for update your laravel project with one command/click.\n\n## Support us\n\nYou can support us by [buying me a coffee](https://github.com/sponsors/salahhusa9) ☕️ .\n\n<!-- docs in salahhusa9.Com/laravel-updater -->\n\n## Docs\nYou find the **docs** in [salahhusa9.com/laravel-updater](https://salahhusa9.com/laravel-updater)\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n## Security Vulnerabilities\n\nPlease review [our security policy](../../security/policy) on how to report security vulnerabilities.\n\n## Credits\n\n- [salahhusa9](https://github.com/salahhusa9)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"salahhusa9/laravel-updater\",\n    \"description\": \"Laravel Updater is a simple yet powerful package for updater your Laravel applications. It makes it easy to upgrade your application to the latest version with just one command.\",\n    \"keywords\": [\n        \"salahhusa9\",\n        \"laravel\",\n        \"laravel-updater\",\n        \"laravel package\",\n        \"laravel self updater\",\n        \"laravel package self updater\",\n        \"laravel package updater\",\n        \"laravel package update\",\n        \"laravel package update itself\"\n    ],\n    \"homepage\": \"https://github.com/salahhusa9/laravel-updater\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"salahhusa9\",\n            \"email\": \"salahhusa9@gmail.com\",\n            \"role\": \"Developer\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^8.1|^8.2\",\n        \"guzzlehttp/guzzle\": \"^7.8\",\n        \"illuminate/contracts\": \"^10.0|^11.0|^12.0\",\n        \"spatie/laravel-package-tools\": \"^1.0\",\n        \"symfony/process\": \"^6.3|^7.0\"\n    },\n    \"require-dev\": {\n        \"laravel/pint\": \"^1.0\",\n        \"nunomaduro/collision\": \"^7.8|^8.0\",\n        \"orchestra/testbench\": \"10.1.0\",\n        \"pestphp/pest\": \"^2.20|^3.0\",\n        \"pestphp/pest-plugin-arch\": \"^2.0|^3.0\",\n        \"pestphp/pest-plugin-laravel\": \"^2.0|^3.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Salahhusa9\\\\Updater\\\\\": \"src/\",\n            \"Salahhusa9\\\\Updater\\\\Database\\\\Factories\\\\\": \"database/factories/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Salahhusa9\\\\Updater\\\\Tests\\\\\": \"tests/\",\n            \"Workbench\\\\App\\\\\": \"workbench/app/\"\n        }\n    },\n    \"scripts\": {\n        \"post-autoload-dump\": \"@composer run prepare\",\n        \"clear\": \"@php vendor/bin/testbench package:purge-laravel-updater --ansi\",\n        \"prepare\": \"@php vendor/bin/testbench package:discover --ansi\",\n        \"build\": [\n            \"@composer run prepare\",\n            \"@php vendor/bin/testbench workbench:build --ansi\"\n        ],\n        \"start\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"@composer run build\",\n            \"@php vendor/bin/testbench serve\"\n        ],\n        \"test\": \"vendor/bin/pest\",\n        \"test-coverage\": \"vendor/bin/pest --coverage\",\n        \"format\": \"vendor/bin/pint\"\n    },\n    \"config\": {\n        \"sort-packages\": true,\n        \"allow-plugins\": {\n            \"pestphp/pest-plugin\": true\n        }\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"Salahhusa9\\\\Updater\\\\UpdaterServiceProvider\"\n            ],\n            \"aliases\": {\n                \"Updater\": \"Salahhusa9\\\\Updater\\\\Facades\\\\Updater\"\n            }\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "config/updater.php",
    "content": "<?php\n\n// config for Salahhusa9/Updater\nreturn [\n\n    'git_path' => 'git',\n\n    'repository_source' => \\Salahhusa9\\Updater\\RepositorySource\\GithubRepository::class,\n    'github_token' => env('GITHUB_TOKEN'),\n    'github_username' => env('GITHUB_USERNAME'),\n    'github_repository' => env('GITHUB_REPOSITORY'),\n\n    'github_timeout' => 100,\n\n    'maintenance_mode' => true,\n    'maintenance_mode_secret' => env('MAINTENANCE_MODE_SECRET', false),\n\n    'before_update_pipelines' => [\n        // you can add your own pipelines here\n    ],\n\n    // run php artisan migrate after update?\n    'migrate' => false,\n\n    // run seeders after update?\n    'seeders' => [\n        // '\\Database\\Seeders\\DatabaseSeeder::class',\n    ],\n\n    // run php artisan cache:clear after update?\n    'cache:clear' => false,\n\n    // run php artisan view:clear after update?\n    'view:clear' => false,\n\n    // run php artisan config:clear after update?\n    'config:clear' => false,\n\n    // run php artisan route:clear after update?\n    'route:clear' => false,\n\n    // run php artisan optimize after update?\n    'optimize' => false,\n\n    'after_update_pipelines' => [\n        // you can add your own pipelines here\n    ],\n\n];\n"
  },
  {
    "path": "database/factories/ModelFactory.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Database\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\n/*\nclass ModelFactory extends Factory\n{\n    protected $model = YourModel::class;\n\n    public function definition()\n    {\n        return [\n\n        ];\n    }\n}\n*/\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/10.2/phpunit.xsd\"\n    backupGlobals=\"false\"\n    bootstrap=\"vendor/autoload.php\"\n    colors=\"true\"\n    processIsolation=\"false\"\n    stopOnFailure=\"false\"\n    executionOrder=\"random\"\n    failOnWarning=\"true\"\n    failOnRisky=\"true\"\n    failOnEmptyTestSuite=\"true\"\n    beStrictAboutOutputDuringTests=\"true\"\n    cacheDirectory=\".phpunit.cache\"\n    backupStaticProperties=\"false\"\n>\n    <testsuites>\n        <testsuite name=\"Salahhusa9 Test Suite\">\n            <directory>tests</directory>\n        </testsuite>\n    </testsuites>\n    <coverage>\n        <report>\n            <html outputDirectory=\"build/coverage\"/>\n            <text outputFile=\"build/coverage.txt\"/>\n            <clover outputFile=\"build/logs/clover.xml\"/>\n        </report>\n    </coverage>\n    <logging>\n        <junit outputFile=\"build/report.junit.xml\"/>\n    </logging>\n    <source>\n        <include>\n            <directory suffix=\".php\">./src</directory>\n        </include>\n    </source>\n</phpunit>\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n    \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n    \"extends\": [\n        \"config:base\"\n    ]\n}\n"
  },
  {
    "path": "resources/views/.gitkeep",
    "content": ""
  },
  {
    "path": "src/Commands/CheckCommand.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Salahhusa9\\Updater\\Events\\NewVersionAvailable;\nuse Salahhusa9\\Updater\\Facades\\Updater;\n\nclass CheckCommand extends Command\n{\n    public $signature = 'updater:check';\n\n    public $description = 'Check for new versions';\n\n    public function handle(): int\n    {\n        $newVersionAvailable = Updater::newVersionAvailable();\n        if (! is_array($newVersionAvailable)) {\n            $this->components->info('No new version available');\n\n            return self::SUCCESS;\n        }\n\n        $this->components->info('New version available: '.$newVersionAvailable['latest_version']);\n\n        event(new NewVersionAvailable($newVersionAvailable['current_version'], $newVersionAvailable['latest_version']));\n\n        return self::SUCCESS;\n    }\n}\n"
  },
  {
    "path": "src/Commands/UpdaterCommand.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Salahhusa9\\Updater\\Facades\\Updater;\n\nclass UpdaterCommand extends Command\n{\n    public $signature = 'updater:update';\n\n    public $description = 'Update the application';\n\n    public function handle(): int\n    {\n        $newVersionAvailable = Updater::newVersionAvailable();\n        if (! is_array($newVersionAvailable)) {\n            $this->components->error('No new version available');\n\n            return self::FAILURE;\n        }\n\n        $this->components->info('Updating to version '.$newVersionAvailable['latest_version']);\n\n        Updater::update(output: function ($message) {\n            $this->components->task($message);\n        });\n\n        $this->components->twoColumnDetail('Application updated', Updater::getCurrentVersion());\n\n        $this->components->info('\n            Thank you for using this package! ❤️\n            Consider supporting my work: \n            https://github.com/sponsors/salahhusa9\n        ');\n\n        return self::SUCCESS;\n    }\n}\n"
  },
  {
    "path": "src/Contracts/Pipeline.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Contracts;\n\ninterface Pipeline\n{\n    public function handle($content, \\Closure $next);\n}\n"
  },
  {
    "path": "src/Contracts/Repository.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Contracts;\n\ninterface Repository\n{\n    public function getLatestVersion(): string;\n\n    public function getLatestVersionData(): \\Illuminate\\Support\\Collection;\n\n    public function getVersions(): array;\n\n    public function getVersionsData(): \\Illuminate\\Support\\Collection;\n}\n"
  },
  {
    "path": "src/Events/NewVersionAvailable.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Events;\n\nuse Illuminate\\Foundation\\Events\\Dispatchable;\nuse Illuminate\\Queue\\SerializesModels;\n\nclass NewVersionAvailable\n{\n    use Dispatchable, SerializesModels;\n\n    public $currentVersion;\n\n    public $newVersion;\n\n    public function __construct($currentVersion, $newVersion)\n    {\n        $this->currentVersion = $currentVersion;\n        $this->newVersion = $newVersion;\n    }\n}\n"
  },
  {
    "path": "src/Events/UpdateFailed.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Events;\n\nuse Illuminate\\Foundation\\Events\\Dispatchable;\nuse Illuminate\\Queue\\SerializesModels;\n\nclass UpdateFailed\n{\n    use Dispatchable, SerializesModels;\n\n    public $pastVersion;\n\n    public $newVersion;\n\n    public $exception;\n\n    public function __construct($pastVersion, $newVersion, $exception)\n    {\n        $this->pastVersion = $pastVersion;\n        $this->newVersion = $newVersion;\n        $this->exception = $exception;\n    }\n}\n"
  },
  {
    "path": "src/Events/UpdatedSuccessfully.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Events;\n\nuse Illuminate\\Foundation\\Events\\Dispatchable;\nuse Illuminate\\Queue\\SerializesModels;\n\nclass UpdatedSuccessfully\n{\n    use Dispatchable, SerializesModels;\n\n    public $pastVersion;\n\n    public $newVersion;\n\n    public function __construct($pastVersion, $newVersion)\n    {\n        $this->pastVersion = $pastVersion;\n        $this->newVersion = $newVersion;\n    }\n}\n"
  },
  {
    "path": "src/Exceptions/GitFailedException.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Exceptions;\n\nuse RuntimeException;\n\nclass GitFailedException extends RuntimeException\n{\n    /**\n     * GitFailedException constructor.\n     *\n     * @param  string  $message\n     */\n    public function __construct($message)\n    {\n        parent::__construct($message);\n    }\n}\n"
  },
  {
    "path": "src/Exceptions/GithubConfigException.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Exceptions;\n\nuse RuntimeException;\n\nclass GithubConfigException extends RuntimeException\n{\n    /**\n     * GithubConfigException constructor.\n     *\n     * @param  string  $message\n     */\n    public function __construct($message)\n    {\n        parent::__construct($message);\n    }\n}\n"
  },
  {
    "path": "src/Facades/Updater.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Facades;\n\nuse Illuminate\\Support\\Facades\\Facade;\n\n/**\n * @see \\Salahhusa9\\Updater\\Updater\n *\n * @method static string update() Update the application to the latest version\n * @method static array newVersionAvailable() Check if a new version is available\n * @method static string getLatestVersion() Get the latest version\n * @method static string getCurrentVersion() Get the current version\n * @method static array getLatestVersionData() Get the latest version data\n * @method static string versions() Get all versions\n */\nclass Updater extends Facade\n{\n    protected static function getFacadeAccessor()\n    {\n        return \\Salahhusa9\\Updater\\Updater::class;\n    }\n}\n"
  },
  {
    "path": "src/Helpers/Git.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Helpers;\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Exceptions\\GitFailedException;\n\nclass Git\n{\n    /**\n     * getCurrentCommit\n     *\n     * @return string\n     *\n     * @throws GitFailedException\n     */\n    public static function getCurrentCommit()\n    {\n        $process = Process::run(self::gitPath().' log --pretty=\"%h\" -n1 HEAD');\n\n        if ($process->failed()) {\n            throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput());\n        }\n\n        return trim($process->output());\n    }\n\n    /**\n     * getCurrentBranch\n     *\n     * @return string\n     *\n     * @throws GitFailedException\n     */\n    public static function getCurrentBranch()\n    {\n        $process = Process::run(self::gitPath().' rev-parse --abbrev-ref HEAD');\n\n        if ($process->failed()) {\n            throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput());\n        }\n\n        return trim($process->output());\n    }\n\n    /**\n     * getCurrentTag\n     *\n     * @return string\n     *\n     * @throws GitFailedException\n     */\n    public static function getCurrentTag()\n    {\n        $process = Process::run(self::gitPath().' describe --tags --abbrev=0');\n\n        if ($process->failed()) {\n            throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput());\n        }\n\n        return trim($process->output());\n    }\n\n    /**\n     * auth\n     *\n     * @return string\n     *\n     * @throws GitFailedException\n     */\n    public static function auth()\n    {\n        $process = Process::run(self::gitPath().' remote set-url origin https://'.config('updater.github_username').':'.config('updater.github_token').'@github.com/'.config('updater.github_username').'/'.config('updater.github_repository').'.git');\n\n        if ($process->failed()) {\n            throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput());\n        }\n\n        return trim($process->output());\n    }\n\n    /**\n     * pull\n     *\n     * @return string\n     *\n     * @throws GitFailedException\n     */\n    public static function pull()\n    {\n        $process = Process::run(self::gitPath().' pull');\n\n        if ($process->failed()) {\n            throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput());\n        }\n\n        return trim($process->output());\n    }\n\n    /**\n     * checkout\n     *\n     * @param  mixed  $branch\n     * @return string\n     *\n     * @throws GitFailedException\n     */\n    public static function checkout($branch)\n    {\n        $process = Process::run(self::gitPath().' checkout '.$branch.' -f');\n\n        if ($process->failed()) {\n            throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput());\n        }\n\n        return trim($process->output());\n    }\n\n    /**\n     * fetch\n     *\n     * @return string\n     *\n     * @throws GitFailedException\n     */\n    public static function fetch()\n    {\n        $process = Process::run(self::gitPath().' fetch');\n\n        if ($process->failed()) {\n            throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput());\n        }\n\n        return trim($process->output());\n    }\n\n    /**\n     * gitPath\n     *\n     * @return string\n     */\n    public static function gitPath()\n    {\n        $gitPath = config('updater.git_path', 'git');\n\n        return $gitPath;\n    }\n}\n"
  },
  {
    "path": "src/Helpers/Helper.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Helpers;\n\nclass Helper\n{\n    /**\n     * isVersion\n     *\n     * @param  mixed  $version\n     */\n    public function isVersion($version): int|false\n    {\n        $pattern = '/^v(\\d+\\.\\d+\\.\\d+)(-[a-zA-Z0-9]+(\\.\\d+)?)?$/';\n\n        return preg_match($pattern, $version);\n    }\n}\n"
  },
  {
    "path": "src/Pipelines/ArtisanCallCacheClearPipe.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Pipelines;\n\nuse Closure;\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Salahhusa9\\Updater\\Contracts\\Pipeline;\n\nclass ArtisanCallCacheClearPipe implements Pipeline\n{\n    /**\n     * handle\n     *\n     * @param  array  $content\n     * @param  mixed  $next\n     * @return void\n     */\n    public function handle($content, Closure $next)\n    {\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Start clearing cache');\n        }\n\n        Artisan::call('cache:clear');\n\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Cache cleared!');\n        }\n\n        return $next($content);\n    }\n}\n"
  },
  {
    "path": "src/Pipelines/ArtisanCallConfigClearPipe.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Pipelines;\n\nuse Closure;\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Salahhusa9\\Updater\\Contracts\\Pipeline;\n\nclass ArtisanCallConfigClearPipe implements Pipeline\n{\n    /**\n     * handle\n     *\n     * @param  array  $content\n     * @param  mixed  $next\n     * @return void\n     */\n    public function handle($content, Closure $next)\n    {\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Start clearing config cache');\n        }\n\n        Artisan::call('config:clear');\n\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Config cache cleared!');\n        }\n\n        return $next($content);\n    }\n}\n"
  },
  {
    "path": "src/Pipelines/ArtisanCallMigratePipe.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Pipelines;\n\nuse Closure;\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Salahhusa9\\Updater\\Contracts\\Pipeline;\n\nclass ArtisanCallMigratePipe implements Pipeline\n{\n    /**\n     * handle\n     *\n     * @param  array  $content\n     * @param  mixed  $next\n     * @return void\n     */\n    public function handle($content, Closure $next)\n    {\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Start migrating');\n        }\n\n        Artisan::call('migrate', [\n            '--force' => true,\n        ]);\n\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Migrated!');\n        }\n\n        return $next($content);\n    }\n}\n"
  },
  {
    "path": "src/Pipelines/ArtisanCallOptimizePipe.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Pipelines;\n\nuse Closure;\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Salahhusa9\\Updater\\Contracts\\Pipeline;\n\nclass ArtisanCallOptimizePipe implements Pipeline\n{\n    /**\n     * handle\n     *\n     * @param  array  $content\n     * @param  mixed  $next\n     * @return void\n     */\n    public function handle($content, Closure $next)\n    {\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Start optimizing');\n        }\n\n        Artisan::call('optimize');\n\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Optimized!');\n        }\n\n        return $next($content);\n    }\n}\n"
  },
  {
    "path": "src/Pipelines/ArtisanCallRouteClearPipe.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Pipelines;\n\nuse Closure;\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Salahhusa9\\Updater\\Contracts\\Pipeline;\n\nclass ArtisanCallRouteClearPipe implements Pipeline\n{\n    /**\n     * handle\n     *\n     * @param  array  $content\n     * @param  mixed  $next\n     * @return void\n     */\n    public function handle($content, Closure $next)\n    {\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Start clearing route cache');\n        }\n\n        Artisan::call('route:clear');\n\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Route cache cleared!');\n        }\n\n        return $next($content);\n    }\n}\n"
  },
  {
    "path": "src/Pipelines/ArtisanCallViewClearPipe.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Pipelines;\n\nuse Closure;\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Salahhusa9\\Updater\\Contracts\\Pipeline;\n\nclass ArtisanCallViewClearPipe implements Pipeline\n{\n    /**\n     * handle\n     *\n     * @param  array  $content\n     * @param  mixed  $next\n     * @return void\n     */\n    public function handle($content, Closure $next)\n    {\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Start clearing view cache');\n        }\n\n        Artisan::call('view:clear');\n\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'View cache cleared!');\n        }\n\n        return $next($content);\n    }\n}\n"
  },
  {
    "path": "src/Pipelines/GitPipe.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Pipelines;\n\nuse Closure;\nuse Salahhusa9\\Updater\\Contracts\\Pipeline;\nuse Salahhusa9\\Updater\\Facades\\Updater;\nuse Salahhusa9\\Updater\\Helpers\\Git;\n\nclass GitPipe implements Pipeline\n{\n    /**\n     * handle\n     *\n     * @param  array  $content\n     * @param  mixed  $next\n     * @return void\n     */\n    public function handle($content, Closure $next)\n    {\n        $version = $content['new_version'];\n\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Start downloading version '.$version);\n        }\n\n        Git::auth();\n        Git::fetch();\n\n        $checkout = Git::checkout($version);\n\n        if ($checkout != 'TEST' and Updater::getCurrentVersion() != $version) {\n            if (is_callable($content['output'])) {\n                call_user_func($content['output'], 'git checkout failed: '.$checkout);\n            }\n\n            throw new \\RuntimeException('git checkout failed: '.$checkout);\n        } else {\n            if (is_callable($content['output'])) {\n                call_user_func($content['output'], 'Checkout success');\n            }\n        }\n\n        return $next($content);\n    }\n}\n"
  },
  {
    "path": "src/Pipelines/SeedersPipe.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Pipelines;\n\nuse Closure;\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Salahhusa9\\Updater\\Contracts\\Pipeline;\n\nclass SeedersPipe implements Pipeline\n{\n    /**\n     * handle\n     *\n     * @param  array  $content\n     * @param  mixed  $next\n     * @return void\n     */\n    public function handle($content, Closure $next)\n    {\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Start seeding');\n        }\n\n        $classes = config('updater.seeders', []);\n\n        foreach ($classes as $class) {\n            Artisan::call('db:seed', [\n                '--class' => $class,\n                '--force' => true,\n            ]);\n        }\n\n        if (is_callable($content['output'])) {\n            call_user_func($content['output'], 'Seeded!');\n        }\n\n        return $next($content);\n    }\n}\n"
  },
  {
    "path": "src/RepositorySource/GithubRepository.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\RepositorySource;\n\nuse Illuminate\\Support\\Facades\\Http;\nuse Salahhusa9\\Updater\\Contracts\\Repository;\nuse Salahhusa9\\Updater\\Exceptions\\GithubConfigException;\n\nclass GithubRepository implements Repository\n{\n    /**\n     * getLatestVersion\n     */\n    public function getLatestVersion(): string\n    {\n        $this->checkConfig();\n\n        return isset($this->getLatestVersionData()['message']) ? throw new \\Exception($this->getLatestVersionData()['message']) : $this->getLatestVersionData()['tag_name'];\n    }\n\n    /**\n     * getLatestVersionData\n     *\n     * @return Illuminate\\Support\\Collection\n     */\n    public function getLatestVersionData(): \\Illuminate\\Support\\Collection\n    {\n        $this->checkConfig();\n\n        $response = Http::withHeaders([\n            'Accept' => 'application/vnd.github.v3+json',\n            'Authorization' => 'Bearer '.config('updater.github_token'),\n            'X-GitHub-Api-Version' => '2022-11-28',\n        ])\n            ->timeout(config('updater.github_timeout', 100))\n            ->get('https://api.github.com/repos/'.config('updater.github_username').'/'.config('updater.github_repository').'/releases/latest');\n\n        return $response->collect();\n    }\n\n    /**\n     * getVersions\n     */\n    public function getVersions(): array\n    {\n        $this->checkConfig();\n\n        $versionsData = $this->getVersionsData();\n\n        if (isset($versionsData['message'])) {\n            throw new \\Exception($versionsData['message']);\n        }\n\n        return $versionsData->map(function ($version) {\n            return $version['tag_name'];\n        })->toArray();\n    }\n\n    /**\n     * getVersionsData\n     *\n     * @return Illuminate\\Support\\Collection\n     */\n    public function getVersionsData(): \\Illuminate\\Support\\Collection\n    {\n        $this->checkConfig();\n\n        $response = Http::withHeaders([\n            'Accept' => 'application/vnd.github.v3+json',\n            'Authorization' => 'Bearer '.config('updater.github_token'),\n            'X-GitHub-Api-Version' => '2022-11-28',\n        ])\n            ->timeout(config('updater.github_timeout', 100))\n            ->get('https://api.github.com/repos/'.config('updater.github_username').'/'.config('updater.github_repository').'/releases');\n\n        return $response->collect();\n    }\n\n    /**\n     * checkConfig\n     *\n     * @return void\n     */\n    public function checkConfig()\n    {\n        if (config('updater.github_token') == null) {\n            throw new GithubConfigException('Please set GITHUB_TOKEN in .env file');\n        }\n\n        if (config('updater.github_username') == null) {\n            throw new GithubConfigException('Please set GITHUB_USERNAME in .env file');\n        }\n\n        if (config('updater.github_repository') == null) {\n            throw new GithubConfigException('Please set GITHUB_REPOSITORY in .env file');\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Updater.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater;\n\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Illuminate\\Support\\Facades\\Pipeline;\nuse Salahhusa9\\Updater\\Contracts\\Repository;\nuse Salahhusa9\\Updater\\Helpers\\Git;\n\nclass Updater\n{\n    private $output;\n\n    /**\n     * update\n     */\n    public function update(?callable $output = null): string\n    {\n        if (! is_null($output) and ! is_callable($output)) {\n            throw new \\RuntimeException('Output must be callable');\n        }\n\n        $this->output = $output;\n\n        if (is_array($this->newVersionAvailable())) {\n            return $this->updateTo($this->getLatestVersion());\n        } else {\n            return 'No new version available';\n        }\n    }\n\n    /**\n     * updateTo\n     *\n     * @param  mixed  $version\n     */\n    private function updateTo($version): string\n    {\n        if (is_array($this->newVersionAvailable()) && $this->newVersionAvailable()['current_version'] != $version) {\n\n            $current_version_in_past = $this->newVersionAvailable()['current_version'];\n\n            try {\n                if (config('updater.maintenance_mode', false)) {\n                    $this->output('Maintenance mode is on, turning it on');\n\n                    Artisan::call(\n                        'down',\n                        config('updater.maintenance_mode_secret', false) ? [\n                            '--secret' => config('updater.maintenance_mode_secret', false),\n                        ] : []\n                    );\n                }\n\n                $pipelines = [\n                    Pipelines\\GitPipe::class,\n                ];\n\n                if (config('updater.before_update_pipelines', false) && is_array(config('updater.before_update_pipelines')) && count(config('updater.before_update_pipelines')) > 0) {\n                    $pipelines = array_merge($pipelines, config('updater.before_update_pipelines'));\n                }\n\n                if (config('updater.migrate', false)) {\n                    $pipelines[] = Pipelines\\ArtisanCallMigratePipe::class;\n                }\n\n                if (config('updater.seeders', false) && is_array(config('updater.seeders')) && count(config('updater.seeders')) > 0) {\n                    $pipelines[] = Pipelines\\SeedersPipe::class;\n                }\n\n                if (config('updater.cache:clear', false)) {\n                    $pipelines[] = Pipelines\\ArtisanCallCacheClearPipe::class;\n                }\n\n                if (config('updater.view:clear', false)) {\n                    $pipelines[] = Pipelines\\ArtisanCallViewClearPipe::class;\n                }\n\n                if (config('updater.config:clear', false)) {\n                    $pipelines[] = Pipelines\\ArtisanCallConfigClearPipe::class;\n                }\n\n                if (config('updater.route:clear', false)) {\n                    $pipelines[] = Pipelines\\ArtisanCallRouteClearPipe::class;\n                }\n\n                if (config('updater.optimize', false)) {\n                    $pipelines[] = Pipelines\\ArtisanCallOptimizePipe::class;\n                }\n\n                if (config('updater.after_update_pipelines', false) && is_array(config('updater.after_update_pipelines')) && count(config('updater.after_update_pipelines')) > 0) {\n                    $pipelines = array_merge($pipelines, config('updater.after_update_pipelines'));\n                }\n\n                // check if pipelines is array and not empty and items is implemented Pipeline contract\n                if (is_array($pipelines) && count($pipelines) > 0) {\n                    foreach ($pipelines as $pipeline) {\n                        if (! is_subclass_of($pipeline, \\Salahhusa9\\Updater\\Contracts\\Pipeline::class)) {\n                            throw new \\RuntimeException('Pipeline '.$pipeline.' is not implemented Pipeline contract:'.\\Salahhusa9\\Updater\\Contracts\\Pipeline::class);\n                        }\n                    }\n                } else {\n                    throw new \\RuntimeException('Pipelines is not array or empty');\n                }\n\n                $this->output('Start Updating to version '.$version);\n\n                Pipeline::send([\n                    'current_version' => $this->getCurrentVersion(),\n                    'new_version' => $version,\n                    'output' => $this->output,\n                ])\n                    ->through($pipelines)\n                    ->then(\n                        function ($content) {\n                            return $content;\n                        }\n                    );\n\n                if (config('updater.maintenance_mode', false)) {\n                    $this->output('Maintenance mode is on, turning it off');\n                    Artisan::call('up');\n                }\n\n                event(new Events\\UpdatedSuccessfully($current_version_in_past, $version));\n\n                return 'Updated to version '.$version;\n            } catch (\\Throwable $th) {\n                if (config('updater.maintenance_mode', false)) {\n                    $this->output('Maintenance mode is on, turning it off');\n                    Artisan::call('up');\n                }\n\n                event(new Events\\UpdateFailed($current_version_in_past, $version, $th->getMessage()));\n\n                throw $th;\n            }\n        } else {\n            $this->output('No new version available');\n\n            return 'No new version available';\n        }\n    }\n\n    /**\n     * output\n     *\n     * @param  mixed  $message\n     */\n    public function output($message): void\n    {\n        if (is_callable($this->output)) {\n            call_user_func($this->output, $message);\n        }\n    }\n\n    /**\n     * newVersionAvailable\n     *\n     * @return bool\n     */\n    public function newVersionAvailable(): bool|array\n    {\n        $currentVersion = $this->getCurrentVersion();\n        $latestVersion = $this->getLatestVersion();\n\n        if ($currentVersion != $latestVersion) {\n            return [\n                'current_version' => $currentVersion,\n                'latest_version' => $latestVersion,\n            ];\n        }\n\n        return false;\n    }\n\n    /**\n     * getCurrentVersion\n     */\n    public function getCurrentVersion(): string\n    {\n        $branch = Git::getCurrentBranch();\n        $tag = Git::getCurrentTag();\n\n        $head = $branch != 'HEAD' ? $branch : $tag;\n\n        return $head;\n    }\n\n    /**\n     * getLatestVersion\n     */\n    public function getLatestVersion(): string\n    {\n        return Cache::remember('latest_version', 5, function () {\n            return app(Repository::class)->getLatestVersion();\n        });\n    }\n\n    /**\n     * getLatestVersionData\n     */\n    public function getLatestVersionData(): array\n    {\n        return Cache::remember('latest_version_data', 5, function () {\n            return app(Repository::class)->getLatestVersionData()->toArray();\n        });\n    }\n\n    /**\n     * versions\n     */\n    public function versions(): array\n    {\n        return Cache::remember('versions', 5, function () {\n            return app(Repository::class)->getVersions();\n        });\n    }\n}\n"
  },
  {
    "path": "src/UpdaterServiceProvider.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater;\n\nuse Salahhusa9\\Updater\\Commands\\CheckCommand;\nuse Salahhusa9\\Updater\\Commands\\UpdaterCommand;\nuse Salahhusa9\\Updater\\Contracts\\Repository;\nuse Salahhusa9\\Updater\\RepositorySource\\GithubRepository;\nuse Spatie\\LaravelPackageTools\\Package;\nuse Spatie\\LaravelPackageTools\\PackageServiceProvider;\n\nclass UpdaterServiceProvider extends PackageServiceProvider\n{\n    public function configurePackage(Package $package): void\n    {\n        /*\n         * This class is a Package Service Provider\n         *\n         * More info: https://github.com/spatie/laravel-package-tools\n         */\n        $package\n            ->name('laravel-updater')\n            ->hasConfigFile()\n            ->hasViews()\n            ->hasCommands(UpdaterCommand::class, CheckCommand::class);\n\n        $this->app->singleton(Repository::class, function () {\n            return new (config('updater.repository_source', GithubRepository::class))();\n        });\n    }\n}\n"
  },
  {
    "path": "tests/ArchTest.php",
    "content": "<?php\n\nit('will not use debugging functions')\n    ->expect(['dd', 'dump', 'ray'])\n    ->each->not->toBeUsed();\n"
  },
  {
    "path": "tests/Commands/CheckCommandTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests;\n\nuse Illuminate\\Support\\Facades\\Event;\nuse Salahhusa9\\Updater\\Commands\\CheckCommand;\nuse Salahhusa9\\Updater\\Events\\NewVersionAvailable;\nuse Salahhusa9\\Updater\\Facades\\Updater;\n\nclass CheckCommandTest extends TestCase\n{\n    /** @test */\n    public function it_does_not_show_any_message_if_no_new_version_is_available()\n    {\n        Updater::shouldReceive('newVersionAvailable')->once()->andReturn(false);\n\n        $this->artisan('updater:check')\n            ->expectsOutputToContain('No new version available')\n            ->assertExitCode(CheckCommand::SUCCESS);\n    }\n\n    /** @test */\n    public function it_shows_a_message_if_a_new_version_is_available()\n    {\n        Updater::shouldReceive('newVersionAvailable')->once()->andReturn([\n            'current_version' => '1.0.0',\n            'latest_version' => '1.1.0',\n        ]);\n\n        $this->artisan('updater:check')\n            ->expectsOutputToContain('New version available: 1.1.0')\n            ->assertExitCode(CheckCommand::SUCCESS);\n    }\n\n    /** @test */\n    public function it_fires_a_new_version_available_event_if_a_new_version_is_available()\n    {\n        Event::fake();\n\n        Updater::shouldReceive('newVersionAvailable')->once()->andReturn([\n            'current_version' => '1.0.0',\n            'latest_version' => '1.1.0',\n        ]);\n\n        $this->artisan('updater:check')\n            ->expectsOutputToContain('New version available: 1.1.0');\n\n        Event::assertDispatched(NewVersionAvailable::class, function ($event) {\n            return $event->currentVersion === '1.0.0' && $event->newVersion === '1.1.0';\n        });\n    }\n}\n"
  },
  {
    "path": "tests/Commands/UpdaterCommandTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Commands;\n\nuse Illuminate\\Support\\Facades\\Http;\nuse Salahhusa9\\Updater\\Facades\\Updater;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass UpdaterCommandTest extends TestCase\n{\n    /** @test */\n    public function it_updates_the_application()\n    {\n        // Mock the Updater facade to return a new version\n        Updater::shouldReceive('newVersionAvailable')\n            ->once()\n            ->andReturn([\n                'current_version' => 'v1.0.0',\n                'latest_version' => 'v1.0.1',\n            ]);\n\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-updater/releases/latest' => Http::response([\n                'tag_name' => 'v1.0.1',\n            ], 200),\n        ]);\n\n        // Mock the Updater facade to return the update command\n        Updater::shouldReceive('getCurrentVersion')\n            ->once()\n            ->andReturn('v1.0.0');\n\n        // Mock the Updater facade to return the update command\n        Updater::shouldReceive('update')\n            ->once()\n            ->andReturn('Updated to version v1.0.1');\n\n        // Call the UpdaterCommand\n        $this->artisan('updater:update')\n            ->expectsOutputToContain('Updating to version v1.0.1')\n            ->expectsOutputToContain('Application updated') // in real life this should be v1.0.1 but we mock it to v1.0.0\n            // ->expectsOutputToContain('v1.0.0') // in real life this should be v1.0.1 but we mock it to v1.0.0\n            // ->expectsOutputToContain('You are now on version') // in real life this should be v1.0.1 but we mock it to v1.0.0\n            ->assertExitCode(0);\n    }\n\n    /** @test */\n    public function it_does_not_update_when_no_new_version_available()\n    {\n        // Mock the Updater facade to return no new version\n        Updater::shouldReceive('newVersionAvailable')\n            ->once()\n            ->andReturn(false);\n\n        // Call the UpdaterCommand\n        $this->artisan('updater:update')\n            ->expectsOutputToContain('No new version available')\n            ->assertExitCode(1);\n    }\n}\n"
  },
  {
    "path": "tests/ExampleTest.php",
    "content": "<?php\n\nit('can test', function () {\n    expect(true)->toBeTrue();\n});\n"
  },
  {
    "path": "tests/GitTest.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass GitTest extends TestCase\n{\n    public function test_get_current_commit(): void\n    {\n        Process::fake([\n            'git log --pretty=\"%h\" -n1 HEAD' => Process::result('commit-hash'),\n        ]);\n\n        // change config git_path to git, because git path changed between windows and linux\n        config()->set('updater.git_path', 'git');\n\n        $this->assertEquals('commit-hash', Salahhusa9\\Updater\\Helpers\\Git::getCurrentCommit());\n    }\n\n    public function test_get_current_commit_failed(): void\n    {\n        $this->expectException(Salahhusa9\\Updater\\Exceptions\\GitFailedException::class);\n        $this->expectExceptionMessage('Test error output');\n\n        Process::fake([\n            'git log --pretty=\"%h\" -n1 HEAD' => Process::result(\n                output: 'Test output',\n                errorOutput: 'Test error output',\n                exitCode: 1,\n            ),\n        ]);\n\n        // change config git_path to git, because git path changed between windows and linux\n        config()->set('updater.git_path', 'git');\n\n        Salahhusa9\\Updater\\Helpers\\Git::getCurrentCommit();\n    }\n\n    public function test_get_current_branch(): void\n    {\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => Process::result('branch-name'),\n        ]);\n\n        // change config git_path to git, because git path changed between windows and linux\n        config()->set('updater.git_path', 'git');\n\n        $this->assertEquals('branch-name', Salahhusa9\\Updater\\Helpers\\Git::getCurrentBranch());\n    }\n\n    public function test_get_current_branch_failed(): void\n    {\n        $this->expectException(Salahhusa9\\Updater\\Exceptions\\GitFailedException::class);\n        $this->expectExceptionMessage('Test error output');\n\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => Process::result(\n                output: 'Test output',\n                errorOutput: 'Test error output',\n                exitCode: 1,\n            ),\n        ]);\n\n        // change config git_path to git, because git path changed between windows and linux\n        config()->set('updater.git_path', 'git');\n\n        Salahhusa9\\Updater\\Helpers\\Git::getCurrentBranch();\n    }\n\n    public function test_get_current_tag(): void\n    {\n        Process::fake([\n            'git describe --tags --abbrev=0' => Process::result('tag-name'),\n        ]);\n\n        // change config git_path to git, because git path changed between windows and linux\n        config()->set('updater.git_path', 'git');\n\n        $this->assertEquals('tag-name', Salahhusa9\\Updater\\Helpers\\Git::getCurrentTag());\n    }\n\n    public function test_get_current_tag_failed(): void\n    {\n        $this->expectException(Salahhusa9\\Updater\\Exceptions\\GitFailedException::class);\n        $this->expectExceptionMessage('Test error output');\n\n        Process::fake([\n            'git describe --tags --abbrev=0' => Process::result(\n                output: 'Test output',\n                errorOutput: 'Test error output',\n                exitCode: 1,\n            ),\n        ]);\n\n        // change config git_path to git, because git path changed between windows and linux\n        config()->set('updater.git_path', 'git');\n\n        Salahhusa9\\Updater\\Helpers\\Git::getCurrentTag();\n    }\n\n    public function test_get_git_path(): void\n    {\n        config()->set('updater.git_path', 'git');\n\n        $this->assertEquals('git', Salahhusa9\\Updater\\Helpers\\Git::gitPath());\n    }\n\n    public function test_git_auth(): void\n    {\n        config()->set('updater.github_token', 'token');\n        config()->set('updater.github_username', 'username');\n        config()->set('updater.github_repository', 'repository');\n\n        Process::fake([\n            'git remote set-url origin https://'.config('updater.github_username').':'.config('updater.github_token').'@github.com/'.config('updater.github_username').'/'.config('updater.github_repository').'.git' => Process::result(''),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n\n        $this->assertEquals('', Salahhusa9\\Updater\\Helpers\\Git::auth());\n    }\n\n    public function test_git_auth_failed(): void\n    {\n        $this->expectException(Salahhusa9\\Updater\\Exceptions\\GitFailedException::class);\n        $this->expectExceptionMessage('Test error output');\n\n        Process::fake([\n            'git remote set-url origin https://'.config('updater.github_username').':'.config('updater.github_token').'@github.com/'.config('updater.github_username').'/'.config('updater.github_repository').'.git' => Process::result(\n                output: 'Test output',\n                errorOutput: 'Test error output',\n                exitCode: 1,\n            ),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n\n        Salahhusa9\\Updater\\Helpers\\Git::auth();\n    }\n\n    public function test_git_pull(): void\n    {\n        Process::fake([\n            'git pull' => Process::result(''),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n\n        $this->assertEquals('', Salahhusa9\\Updater\\Helpers\\Git::pull());\n    }\n\n    public function test_git_pull_failed(): void\n    {\n        $this->expectException(Salahhusa9\\Updater\\Exceptions\\GitFailedException::class);\n        $this->expectExceptionMessage('Test error output');\n\n        Process::fake([\n            'git pull' => Process::result(\n                output: 'Test output',\n                errorOutput: 'Test error output',\n                exitCode: 1,\n            ),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n\n        Salahhusa9\\Updater\\Helpers\\Git::pull();\n    }\n\n    public function test_git_checkout(): void\n    {\n        Process::fake([\n            'git checkout branch-name -f' => Process::result(''),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n\n        $this->assertEquals('', Salahhusa9\\Updater\\Helpers\\Git::checkout('branch-name'));\n    }\n\n    public function test_git_checkout_failed(): void\n    {\n        $this->expectException(Salahhusa9\\Updater\\Exceptions\\GitFailedException::class);\n        $this->expectExceptionMessage('Test error output');\n\n        Process::fake([\n            'git checkout branch-name -f' => Process::result(\n                output: 'Test output',\n                errorOutput: 'Test error output',\n                exitCode: 1,\n            ),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n\n        Salahhusa9\\Updater\\Helpers\\Git::checkout('branch-name');\n    }\n\n    public function test_git_fetch(): void\n    {\n        Process::fake([\n            'git fetch' => Process::result(''),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n\n        $this->assertEquals('', Salahhusa9\\Updater\\Helpers\\Git::fetch());\n    }\n\n    public function test_git_fetch_failed(): void\n    {\n        $this->expectException(Salahhusa9\\Updater\\Exceptions\\GitFailedException::class);\n        $this->expectExceptionMessage('Test error output');\n\n        Process::fake([\n            'git fetch' => Process::result(\n                output: 'Test output',\n                errorOutput: 'Test error output',\n                exitCode: 1,\n            ),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n\n        Salahhusa9\\Updater\\Helpers\\Git::fetch();\n    }\n}\n"
  },
  {
    "path": "tests/HelperTest.php",
    "content": "<?php\n\nuse PHPUnit\\Framework\\TestCase;\nuse Salahhusa9\\Updater\\Helpers\\Helper;\n\nclass HelperTest extends TestCase\n{\n    public function test_is_version_returns_true_for_valid_version()\n    {\n        $helper = new Helper;\n\n        $this->assertEquals($helper->isVersion('v1.2.3'), 1);\n    }\n\n    public function test_is_version_returns_false_for_invalid_version()\n    {\n        $helper = new Helper;\n\n        $this->assertEqualsCanonicalizing($helper->isVersion('invalid-version'), 0);\n    }\n}\n"
  },
  {
    "path": "tests/Pest.php",
    "content": "<?php\n\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nuses(TestCase::class)->in(__DIR__);\n"
  },
  {
    "path": "tests/Pipelines/ArtisanCallCacheClearPipeTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Pipelines;\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Pipelines\\ArtisanCallCacheClearPipe;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass ArtisanCallCacheClearPipeTest extends TestCase\n{\n    public function test_run_handle()\n    {\n        Process::fake([\n            '*' => Process::result('cache:clear'),\n        ]);\n\n        $messages = [\n            'Start clearing cache',\n            'Cache cleared!',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        app()->make(ArtisanCallCacheClearPipe::class)->handle($content, $next);\n    }\n}\n"
  },
  {
    "path": "tests/Pipelines/ArtisanCallConfigClearPipeTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Pipelines;\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Pipelines\\ArtisanCallConfigClearPipe;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass ArtisanCallConfigClearPipeTest extends TestCase\n{\n    public function test_run_handle()\n    {\n        Process::fake([\n            '*' => Process::result('config:clear'),\n        ]);\n\n        $messages = [\n            'Start clearing config cache',\n            'Config cache cleared!',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        app()->make(ArtisanCallConfigClearPipe::class)->handle($content, $next);\n    }\n}\n"
  },
  {
    "path": "tests/Pipelines/ArtisanCallMigratePipeTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Pipelines;\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Pipelines\\ArtisanCallMigratePipe;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass ArtisanCallMigratePipeTest extends TestCase\n{\n    public function test_run_handle()\n    {\n        Process::fake([\n            '*' => Process::result('migrate'),\n        ]);\n\n        $messages = [\n            'Start migrating',\n            'Migrated!',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        app()->make(ArtisanCallMigratePipe::class)->handle($content, $next);\n    }\n}\n"
  },
  {
    "path": "tests/Pipelines/ArtisanCallOptimizePipeTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Pipelines;\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Pipelines\\ArtisanCallOptimizePipe;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass ArtisanCallOptimizePipeTest extends TestCase\n{\n    public function test_run_handle()\n    {\n        Process::fake([\n            '*' => Process::result('optimize'),\n        ]);\n\n        $messages = [\n            'Start optimizing',\n            'Optimized!',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        app()->make(ArtisanCallOptimizePipe::class)->handle($content, $next);\n    }\n}\n"
  },
  {
    "path": "tests/Pipelines/ArtisanCallRouteClearPipeTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Pipelines;\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Pipelines\\ArtisanCallRouteClearPipe;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass ArtisanCallRouteClearPipeTest extends TestCase\n{\n    public function test_run_handle()\n    {\n        Process::fake([\n            '*' => Process::result('route:clear'),\n        ]);\n\n        $messages = [\n            'Start clearing route cache',\n            'Route cache cleared!',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        app()->make(ArtisanCallRouteClearPipe::class)->handle($content, $next);\n    }\n}\n"
  },
  {
    "path": "tests/Pipelines/ArtisanCallViewClearPipeTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Pipelines;\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Pipelines\\ArtisanCallViewClearPipe;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass ArtisanCallViewClearPipeTest extends TestCase\n{\n    public function test_run_handle()\n    {\n        Process::fake([\n            '*' => Process::result('view:clear'),\n        ]);\n\n        $messages = [\n            'Start clearing view cache',\n            'View cache cleared!',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        app()->make(ArtisanCallViewClearPipe::class)->handle($content, $next);\n    }\n}\n"
  },
  {
    "path": "tests/Pipelines/GitPipeTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Pipelines;\n\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Pipelines\\GitPipe;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass GitPipeTest extends TestCase\n{\n    public function test_run_handle()\n    {\n        Process::fake([\n            '*' => Process::result('1.0.0'), // this for return $version in getCurrentVersion()\n        ]);\n\n        $messages = [\n            'Start downloading version 1.0.0',\n            'Checkout success',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n            'new_version' => '1.0.0',\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        app()->make(GitPipe::class)->handle($content, $next);\n    }\n\n    public function test_run_handle_with_error()\n    {\n        $this->expectException(\\Exception::class);\n\n        Process::fake([\n            '*' => Process::result('error'), // this for throw new \\Exception('git checkout failed: '.$checkout); becouse $checkout = Git::checkout($version); return error\n        ]);\n\n        $messages = [\n            'Start downloading version 1.0.0',\n            'git checkout failed: error',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n            'new_version' => '1.0.0',\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        app()->make(GitPipe::class)->handle($content, $next);\n    }\n}\n"
  },
  {
    "path": "tests/Pipelines/SeedersPipeTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\Pipelines;\n\nuse Salahhusa9\\Updater\\Pipelines\\SeedersPipe;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass SeedersPipeTest extends TestCase\n{\n    public function test_run_handle()\n    {\n        $messages = [\n            'Start seeding',\n            'Seeded!',\n        ];\n\n        $content = [\n            'output' => function ($message) use ($messages) {\n                $this->assertTrue(in_array($message, $messages));\n            },\n        ];\n\n        $next = function ($result) use ($content) {\n            $this->assertEquals($result, $content);\n        };\n\n        config()->set('updater.seeders', [\n\n        ]);\n\n        app()->make(SeedersPipe::class)->handle($content, $next);\n    }\n}\n"
  },
  {
    "path": "tests/RepositorySource/GithubRepositoryTest.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests\\RepositorySource;\n\nuse Illuminate\\Support\\Facades\\Http;\nuse Salahhusa9\\Updater\\Exceptions\\GithubConfigException;\nuse Salahhusa9\\Updater\\RepositorySource\\GithubRepository;\n\nclass GithubRepositoryTest extends \\Salahhusa9\\Updater\\Tests\\TestCase\n{\n    /** @test */\n    public function config_check()\n    {\n        // set env\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-updater');\n\n        $githubRepository = new GithubRepository;\n\n        $this->assertTrue($githubRepository->checkConfig());\n    }\n\n    /** @test */\n    public function config_check_exception()\n    {\n        $this->expectException(GithubConfigException::class);\n\n        $githubRepository = new GithubRepository;\n\n        $this->assertTrue($githubRepository->checkConfig());\n    }\n\n    /** @test */\n    public function it_can_get_latest_version()\n    {\n        // set env\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-updater');\n\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-updater/releases/latest' => Http::response([\n                'tag_name' => 'v1.0.0',\n            ], 200),\n        ]);\n\n        $githubRepository = new GithubRepository;\n\n        $this->assertEquals('v1.0.0', $githubRepository->getLatestVersion());\n    }\n\n    /** @test */\n    public function it_can_get_latest_version_data()\n    {\n        // set env\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-updater');\n\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-updater/releases/latest' => Http::response([\n                'tag_name' => 'v1.0.0',\n            ], 200),\n        ]);\n\n        $githubRepository = new GithubRepository;\n\n        $this->assertIsArray($githubRepository->getLatestVersionData()->toArray());\n    }\n\n    /** @test */\n    public function it_can_get_versions()\n    {\n        // set env\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-updater');\n\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-updater/releases' => Http::response([\n                [\n                    'tag_name' => 'v1.0.0',\n                ],\n                [\n                    'tag_name' => 'v1.0.1',\n                ],\n            ], 200),\n        ]);\n\n        $githubRepository = new GithubRepository;\n\n        $this->assertIsArray($githubRepository->getVersions());\n    }\n\n    /** @test */\n    public function it_can_get_versions_data()\n    {\n        // set env\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-updater');\n\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-updater/releases' => Http::response([\n                [\n                    'tag_name' => 'v1.0.0',\n                ],\n                [\n                    'tag_name' => 'v1.0.1',\n                ],\n            ], 200),\n        ]);\n\n        $githubRepository = new GithubRepository;\n\n        $this->assertIsArray($githubRepository->getVersionsData()->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\nnamespace Salahhusa9\\Updater\\Tests;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\nuse Orchestra\\Testbench\\TestCase as Orchestra;\nuse Salahhusa9\\Updater\\UpdaterServiceProvider;\n\nclass TestCase extends Orchestra\n{\n    protected function setUp(): void\n    {\n        parent::setUp();\n\n        Factory::guessFactoryNamesUsing(\n            fn (string $modelName) => 'Salahhusa9\\\\Updater\\\\Database\\\\Factories\\\\'.class_basename($modelName).'Factory'\n        );\n    }\n\n    protected function getPackageProviders($app)\n    {\n        return [\n            UpdaterServiceProvider::class,\n        ];\n    }\n\n    public function getEnvironmentSetUp($app)\n    {\n        config()->set('database.default', 'testing');\n\n        /*\n        $migration = include __DIR__.'/../database/migrations/create_laravel-updater_table.php.stub';\n        $migration->up();\n        */\n    }\n}\n"
  },
  {
    "path": "tests/UpdaterTest.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Illuminate\\Support\\Facades\\Event;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Process;\nuse Salahhusa9\\Updater\\Facades\\Updater;\nuse Salahhusa9\\Updater\\Tests\\TestCase;\n\nclass UpdaterTest extends TestCase\n{\n    public function test_get_current_version()\n    {\n        config()->set('updater.git_path', 'git');\n\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => 'HEAD',\n            'git describe --tags --abbrev=0' => '1.0.0',\n        ]);\n\n        $this->assertEquals('1.0.0', Updater::getCurrentVersion());\n    }\n\n    public function test_get_latest_version()\n    {\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-test/releases/latest' => Http::response([\n                'tag_name' => '1.0.1',\n            ], 200),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-test');\n\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => 'HEAD',\n            'git describe --tags --abbrev=0' => '1.0.0',\n            'git pull' => '',\n            'git checkout 1.0.1' => 'TEST',\n            'git remote set-url origin https://salahhusa9:salahhusa9@github.com/salahhusa9/laravel-test.git' => '',\n            'git fetch' => '',\n        ]);\n\n        $this->assertEquals('1.0.1', Updater::getLatestVersion());\n    }\n\n    public function test_get_latest_version_data()\n    {\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-test/releases/latest' => Http::response([\n                'tag_name' => '1.0.1',\n            ], 200),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-test');\n\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => 'HEAD',\n            'git describe --tags --abbrev=0' => '1.0.0',\n            'git pull' => '',\n            'git checkout 1.0.1' => 'TEST',\n            'git remote set-url origin https://salahhusa9:salahhusa9@github.com/salahhusa9/laravel-test.git' => '',\n            'git fetch' => '',\n        ]);\n\n        $this->assertEquals(['tag_name' => '1.0.1'], Updater::getLatestVersionData());\n    }\n\n    public function test_versions()\n    {\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-test/releases' => Http::response([\n                [\n                    'tag_name' => '1.0.0',\n                ],\n                [\n                    'tag_name' => '1.1.0',\n                ],\n                [\n                    'tag_name' => '2.0.0',\n                ],\n            ], 200),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-test');\n\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => 'HEAD',\n            'git describe --tags --abbrev=0' => '1.0.0',\n            'git pull' => '',\n            'git checkout 1.0.1' => 'TEST',\n            'git remote set-url origin https://salahhusa9:salahhusa9@github.com/salahhusa9/laravel-test.git' => '',\n            'git fetch' => '',\n        ]);\n\n        $this->assertEquals(['1.0.0', '1.1.0', '2.0.0'], Updater::versions());\n    }\n\n    public function test_new_version_available()\n    {\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-test/releases/latest' => Http::response([\n                'tag_name' => '1.0.1',\n            ], 200),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-test');\n\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => 'HEAD',\n            'git describe --tags --abbrev=0' => '1.0.0',\n            'git pull' => '',\n            'git checkout 1.0.1' => 'TEST',\n            'git remote set-url origin https://salahhusa9:salahhusa9@github.com/salahhusa9/laravel-test.git' => '',\n            'git fetch' => '',\n        ]);\n\n        $this->assertEquals(['current_version' => '1.0.0', 'latest_version' => '1.0.1'], Updater::newVersionAvailable());\n    }\n\n    public function test_update()\n    {\n        Event::fake();\n        // Artisan::fake();\n\n        Http::fake([\n            'https://api.github.com/repos/salahhusa9/laravel-test/releases/latest' => Http::response([\n                'tag_name' => '1.0.1',\n            ], 200),\n        ]);\n\n        config()->set('updater.git_path', 'git');\n        config()->set('updater.github_token', 'salahhusa9');\n        config()->set('updater.github_username', 'salahhusa9');\n        config()->set('updater.github_repository', 'laravel-test');\n\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => 'HEAD',\n            'git describe --tags --abbrev=0' => '1.0.0',\n            'git pull' => '',\n            'git checkout 1.0.1 -f' => 'TEST',\n            'git remote set-url origin https://salahhusa9:salahhusa9@github.com/salahhusa9/laravel-test.git' => '',\n            'git fetch' => '',\n        ]);\n\n        // Artisan::shouldReceive('call')->once()->with('up');\n        $this->assertEquals('Updated to version 1.0.1', Updater::update());\n\n        // Test update failure\n        Process::fake([\n            'git rev-parse --abbrev-ref HEAD' => 'HEAD',\n            'git describe --tags --abbrev=0' => '1.0.0',\n            'git pull origin HEAD' => '',\n            'git checkout 1.0.1 -f' => '...',\n            'git remote set-url origin https://salahhusa9:salahhusa9@github.com/salahhusa9/laravel-test.git' => '',\n            'git fetch' => '',\n        ]);\n\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('git checkout failed: ...');\n        Updater::update();\n    }\n}\n"
  },
  {
    "path": "workbench/app/Providers/WorkbenchServiceProvider.php",
    "content": "<?php\n\nnamespace Workbench\\App\\Providers;\n\nuse Illuminate\\Support\\Facades\\Route;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass WorkbenchServiceProvider extends ServiceProvider\n{\n    /**\n     * Register services.\n     */\n    public function register(): void\n    {\n        //\n    }\n\n    /**\n     * Bootstrap services.\n     */\n    public function boot(): void\n    {\n        Route::view('/', 'welcome');\n    }\n}\n"
  }
]