You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ma...@apache.org on 2024/03/25 23:55:08 UTC

(superset) 01/04: feat: make supersetbot do what dependabot should do

This is an automated email from the ASF dual-hosted git repository.

maximebeauchemin pushed a commit to branch pyproject.toml
in repository https://gitbox.apache.org/repos/asf/superset.git

commit fbf765ffd36970eae5c67bcec75a4254f0b29af0
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Mon Mar 25 13:03:24 2024 -0700

    feat: make supersetbot do what dependabot should do
---
 .github/supersetbot/src/cli.js    | 10 ++++++-
 .github/supersetbot/src/github.js | 52 +++++++++++++++++++++++++++++++++++
 .github/supersetbot/src/utils.js  | 57 +++++++++++++++++----------------------
 .github/workflows/supersetbot.yml |  1 +
 4 files changed, 86 insertions(+), 34 deletions(-)

diff --git a/.github/supersetbot/src/cli.js b/.github/supersetbot/src/cli.js
index 4b4612ee97..4cefa3567f 100755
--- a/.github/supersetbot/src/cli.js
+++ b/.github/supersetbot/src/cli.js
@@ -151,6 +151,14 @@ export default function getCLI(context) {
         await github.assignOrgLabel(opts.issue, opts.verbose, opts.dryRun);
       });
 
+    program.command('auto-bump <python-lib>')
+      .description('Submit a PR to bump the version of a package')
+      .action(async function (pythonLib) {
+        const opts = context.processOptions(this, ['repo']);
+        const github = new Github({ context });
+        github.createBumpLibPullRequest(pythonLib, opts.verbose, opts.dryRun);
+      });
+
 
     program.command('docker')
       .description('Generates/run docker build commands use in CI')
@@ -166,7 +174,7 @@ export default function getCLI(context) {
         const cmd = docker.getDockerCommand({ ...opts });
         context.log(cmd);
         if (!opts.dryRun) {
-          utils.runShellCommand(cmd, false);
+          utils.runShellCommand({ cmd, raiseOnError: false });
         }
       });
   }
diff --git a/.github/supersetbot/src/github.js b/.github/supersetbot/src/github.js
index 39d3e42e9f..f94b350de5 100644
--- a/.github/supersetbot/src/github.js
+++ b/.github/supersetbot/src/github.js
@@ -1,7 +1,12 @@
+import fs from 'fs';
+import os from 'os';
+import path from 'path';
+
 import { Octokit } from '@octokit/rest';
 import { throttling } from '@octokit/plugin-throttling';
 
 import { ORG_LIST, PROTECTED_LABEL_PATTERNS, COMMITTER_TEAM } from './metadata.js';
+import { runShellCommand } from './utils.js';
 
 class Github {
   #userInTeamCache;
@@ -247,6 +252,53 @@ class Github {
   static isLabelProtected(label) {
     return PROTECTED_LABEL_PATTERNS.some((pattern) => new RegExp(pattern).test(label));
   }
+
+  createBumpLibPullRequest(lib, verbose = false, dryRun = false) {
+    const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'update-'));
+    console.log("CWD:", cwd);
+
+    // Clone the repo
+    runShellCommand({ command: `git clone --depth 1 git@github.com:${this.context.repo} .`, cwd, verbose });
+
+    // Run pip-compile-multi
+    runShellCommand({ command: `pip-compile-multi -P ${lib}`, cwd });
+
+    // Check for changes
+    const status = runShellCommand({ command: 'git status --porcelain', cwd, raiseOnError: false, verbose });
+    if (!!status) {
+      console.log('No changes detected... skipping.');
+    } else {
+
+      // Create branch
+      const branchName = `bump-${lib}-${Date.now()}`;
+      runShellCommand({ command: `git checkout -b ${branchName}`, cwd, verbose });
+
+      // Commit changes
+      runShellCommand({ command: `git add .`, cwd });
+      const commitMessage = `chore(supersetbot): bump python library "${lib}"`;
+      runShellCommand({ command: `git commit -m "${commitMessage}"`, cwd, verbose });
+
+      // Push changes
+      runShellCommand({ command: `git push origin ${branchName}`, cwd, verbose });
+
+      if (!dryRun) {
+        // Create a PR
+        this.octokit.pulls.create({
+            ...this.unPackRepo(),
+            title: commitMessage,
+            head: branchName,
+            base: 'master',
+            body: `Updates the python "${lib}" library version. \n\nGenerated by @supersetbot 🤖`,
+        })
+        .then(({ data }) => {
+            console.log(`Pull request created: ${data.html_url}`);
+        })
+        .catch(console.error);
+      }
+    }
+    // Cleaning up
+    fs.rmSync(cwd, { recursive: true, force: true });
+  }
 }
 
 export default Github;
diff --git a/.github/supersetbot/src/utils.js b/.github/supersetbot/src/utils.js
index 97c6b2d8f5..07777c378e 100644
--- a/.github/supersetbot/src/utils.js
+++ b/.github/supersetbot/src/utils.js
@@ -17,7 +17,8 @@
  * under the License.
  */
 
-import { spawn } from 'child_process';
+import { spawnSync } from 'child_process';
+
 import { readFile } from 'fs/promises';
 import { fileURLToPath } from 'url';
 import path from 'path';
@@ -40,39 +41,29 @@ export async function currentPackageVersion() {
   return data.version;
 }
 
-export function runShellCommand(command, raiseOnError = true) {
-  return new Promise((resolve, reject) => {
-    // Split the command string into an array of arguments
-    const args = command.split(/\s+/).filter((s) => !!s && s !== '\\');
-    const childProcess = spawn(args.shift(), args);
-    let stdoutData = '';
-    let stderrData = '';
+export function runShellCommand({ command, raiseOnError = true, exitOnError = true, cwd = null, verbose = false }) {
+  const args = command.split(/\s+/).filter((s) => !!s && s !== '\\');
+  const spawnOptions = { stdio: 'inherit', shell: true };
+  if (verbose) {
+    console.log(`RUN: ${command}`);
+  }
+  if (cwd) {
+    spawnOptions.cwd = cwd;
+  }
 
-    // Capture stdout data
-    childProcess.stdout.on('data', (data) => {
-      stdoutData += data;
-      console.log(`stdout: ${data}`);
-    });
+  const result = spawnSync(args.shift(), args, spawnOptions);
 
-    // Capture stderr data
-    childProcess.stderr.on('data', (data) => {
-      stderrData += data;
-      console.error(`stderr: ${data}`);
-    });
+  if (result.status !== 0) {
+    const msg = `Command failed with exit code ${result.status}: ${result.stderr?.toString()}`;
+    console.error(msg);
+
+    if (raiseOnError) {
+      throw new Error(msg);
+    }
+    if (exitOnError) {
+      process.exit(1);
+    }
+  }
 
-    // Handle process exit
-    childProcess.on('close', (code) => {
-      if (code === 0) {
-        resolve(stdoutData);
-      } else {
-        const msg = `Command failed with code ${code}: ${stderrData}`;
-        if (raiseOnError) {
-          reject(new Error(msg));
-        } else {
-          console.error(msg);
-          process.exit(1);
-        }
-      }
-    });
-  });
+  return result.stdout?.toString();
 }
diff --git a/.github/workflows/supersetbot.yml b/.github/workflows/supersetbot.yml
index f336629676..cafda9b74b 100644
--- a/.github/workflows/supersetbot.yml
+++ b/.github/workflows/supersetbot.yml
@@ -51,6 +51,7 @@ jobs:
           COMMENT_BODY: ${{ github.event.comment.body }}
           INPUT_COMMENT_BODY: ${{ github.event.inputs.comment_body }}
         run: |
+          npm install -g supersetbot
           cat <<EOF > script.js
           const run = async () => {
             const { runCommandFromGithubAction } = await import('supersetbot');