diff --git a/.github/update_packages.php b/.github/update_packages.php new file mode 100644 index 00000000..4e472150 --- /dev/null +++ b/.github/update_packages.php @@ -0,0 +1,171 @@ +get($url); + $data = json_decode($response->getBody(), TRUE); + + $versions = array_keys($data['packages'][$packageName]); + usort($versions, 'version_compare'); + + $latestVersion = end($versions); + + // Extract major.minor version (e.g., "13.3.3" becomes "13.x") + $versionParts = explode('.', $latestVersion); + if (count($versionParts) > 1) { + return $versionParts[0] . '.x'; + } + + return NULL; + } + catch (RequestException $e) { + return NULL; + } +} + +/** + * Fetches the latest version of a package from Drupal.org. + * + * @param string $packageName + * The name of the package. + * + * @return string|null + * The latest version string, or NULL if not found. + */ +function get_latest_version_from_drupal_org(string $packageName) { + $client = new Client(); + // Remove "drupal/" prefix. + $packageName = str_replace('drupal/', '', $packageName); + $drupalApiUrl = "https://www.drupal.org/api-d7/node.json?field_project_machine_name={$packageName}"; + + try { + $response = $client->get($drupalApiUrl); + $data = json_decode($response->getBody(), TRUE); + + if (!empty($data['list']) && isset($data['list'][0]['field_release_version'])) { + return $data['list'][0]['field_release_version']; + } + + echo "No new releases found for {$packageName} on Drupal.org.\n"; + return NULL; + } + catch (RequestException $e) { + echo "Error fetching data for {$packageName} on Drupal.org: " . $e->getMessage() . PHP_EOL; + return NULL; + } +} + +/** + * Determines if latest version is a major update compared to current version. + * + * @param string|null $currentVersion + * The current version. + * @param string|null $latestVersion + * The latest version. + * + * @return bool + * TRUE if it is a major update, FALSE otherwise. + */ +function is_major_update(?string $currentVersion, ?string $latestVersion) { + if (!$currentVersion || !$latestVersion) { + return FALSE; + } + + $currentMajor = explode('.', $currentVersion)[0]; + $latestMajor = explode('.', $latestVersion)[0]; + + return $currentMajor !== $latestMajor; +} + +/** + * Updates package versions in a YAML file. + * + * @param string $filePath + * The path to the YAML file. + */ +function update_packages_yaml(string $filePath) { + $fileLines = file($filePath); + $comments = []; + + // Extract comments. + foreach ($fileLines as $line) { + if (preg_match('/^\s*#/', $line)) { + $comments[] = $line; + } + } + + $packages = Yaml::parseFile($filePath); + + foreach ($packages as $package => &$details) { + if (isset($details['core_matrix'])) { + // Update only '*' entry. + if (isset($details['core_matrix']['*'])) { + $currentVersion = $details['core_matrix']['*']['version'] ?? NULL; + $latestVersion = get_latest_version($package); + + if ($latestVersion && is_major_update($currentVersion, $latestVersion)) { + $details['core_matrix']['*']['version'] = $latestVersion; + echo "Updated $package for '*' to version $latestVersion.\n"; + } + } + else { + echo "Skipping $package as '*' is not defined in core_matrix.\n"; + } + } + else { + // Update non-core_matrix packages. + $currentVersion = $details['version'] ?? NULL; + $latestVersion = get_latest_version($package); + + if ($latestVersion && is_major_update($currentVersion, $latestVersion)) { + $details['version'] = $latestVersion; + echo "Updated $package to version $latestVersion.\n"; + } + } + } + + // Write back the YAML, appending the comments. + file_put_contents($filePath, implode('', $comments) . "\n" . Yaml::dump($packages, 2)); +} + +// File path to the YAML configuration. +$filePath = __DIR__ . '/../config/packages.yml'; + +update_packages_yaml($filePath); diff --git a/.github/workflows/update-packages.yml b/.github/workflows/update-packages.yml new file mode 100644 index 00000000..a2312beb --- /dev/null +++ b/.github/workflows/update-packages.yml @@ -0,0 +1,73 @@ +name: Update Packages and Create Pull Request + +on: + schedule: + - cron: '0 0 * * 1' # Weekly on Mondays + push: + branches: + - wip + paths-ignore: + - .idea/** + - docs/** + +permissions: + contents: write + pull-requests: write + +jobs: + update-packages: + runs-on: ubuntu-latest + + steps: + # Step 1: Checkout Code + - name: Checkout Code + uses: actions/checkout@v3 + + # Step 2: Set Up PHP + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + tools: composer + + # Step 3: Add Guzzle Dependency + - name: Add Guzzle Dependency + run: composer require guzzlehttp/guzzle:^7.4 + + # Step 4: Install Dependencies + - name: Install Dependencies + run: composer install + + # Step 5: Reset Composer Changes + - name: Reset Composer Changes + run: git checkout -- composer.json composer.lock + + # Step 6: Run Update Script and Commit Changes + - name: Run Update Script + run: | + TIMESTAMP=$(date +'%Y%m%d%H%M%S') + BRANCH_NAME="update-packages-${TIMESTAMP}" + echo "branch_name=${BRANCH_NAME}" >> $GITHUB_ENV + git config --local user.name "github-actions[bot]" + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git fetch + git checkout -b "$BRANCH_NAME" origin/develop + git cherry-pick HEAD@{1} + php .github/update_packages.php + git status + git add config/packages.yml + git commit -m "Update dependencies in packages.yml" + git show-branch + git push origin "$BRANCH_NAME" + + # Step 7: Create Pull Request + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ env.branch_name }} + base: develop + title: "Update packages.yml with latest versions" + body: | + This pull request updates the `packages.yml` file with the latest stable versions of dependencies. + labels: dependencies