Edits history of script submission #5813 for ' Sync script to Git repo (windmill)'

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing ${path_type} ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      let repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const azureMatch = repo_url.match(/AZURE_DEVOPS_TOKEN\((?<url>.+)\)/);
    
      if (azureMatch) {
        console.log(
          "Requires Azure DevOps service account access token, requesting..."
        );
        const azureResource = await wmillclient.getResource(azureMatch.groups.url);
    
        const response = await fetch(
          `https://login.microsoftonline.com/${azureResource.azureTenantId}/oauth2/token`,
          {
            method: "POST",
            body: new URLSearchParams({
              client_id: azureResource.azureClientId,
              client_secret: azureResource.azureClientSecret,
              grant_type: "client_credentials",
              resource: "499b84ac-1321-427f-aa17-267ca6975798/.default",
            }),
          }
        );
    
        const { access_token } = await response.json();
    
        repo_url = repo_url.replace(azureMatch[0], access_token);
      }
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${(path ?? parent_path)
            ?.split("/")
            .slice(0, 2)
            .join("__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${(
            path ?? parent_path
          )?.replaceAll("/", "__")}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least one staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        try {
            await sh_run(undefined, "git", "push", "--porcelain");
        } catch {
            console.log("Could not push, trying to rebase first");
            await sh_run(undefined, "git", "pull", "--rebase");
            await sh_run(undefined, "git", "push", "--porcelain");
        }
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${nargs.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw Error(err);
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } if (path_type == "app") {
        return `${path}.app/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by admin 668 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing ${path_type} ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      let repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const azureMatch = repo_url.match(/AZURE_DEVOPS_TOKEN\((?<url>.+)\)/);
    
      if (azureMatch) {
        console.log(
          "Requires Azure DevOps service account access token, requesting..."
        );
        const azureResource = await wmillclient.getResource(azureMatch.groups.url);
    
        const response = await fetch(
          `https://login.microsoftonline.com/${azureResource.azureTenantId}/oauth2/token`,
          {
            method: "POST",
            body: new URLSearchParams({
              client_id: azureResource.azureClientId,
              client_secret: azureResource.azureClientSecret,
              grant_type: "client_credentials",
              resource: "499b84ac-1321-427f-aa17-267ca6975798/.default",
            }),
          }
        );
    
        const { access_token } = await response.json();
    
        repo_url = repo_url.replace(azureMatch[0], access_token);
      }
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${(path ?? parent_path)
            ?.split("/")
            .slice(0, 2)
            .join("__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${(
            path ?? parent_path
          )?.replaceAll("/", "__")}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${nargs.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw Error(err);
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } if (path_type == "app") {
        return `${path}.app/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 686 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing ${path_type} ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      let repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const azureMatch = repo_url.match(/AZURE_DEVOPS_TOKEN\((?<url>.+)\)/);
    
      if (azureMatch) {
        console.log(
          "Requires Azure DevOps service account access token, requesting..."
        );
        const azureResource = await wmillclient.getResource(azureMatch.groups.url);
    
        const response = await fetch(
          `https://login.microsoftonline.com/${azureResource.azureTenantId}/oauth2/token`,
          {
            method: "POST",
            body: new URLSearchParams({
              client_id: azureResource.azureClientId,
              client_secret: azureResource.azureClientSecret,
              grant_type: "client_credentials",
              resource: "499b84ac-1321-427f-aa17-267ca6975798/.default",
            }),
          }
        );
    
        const { access_token } = await response.json();
    
        repo_url = repo_url.replace(azureMatch[0], access_token);
      }
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${(path ?? parent_path)
            ?.split("/")
            .slice(0, 2)
            .join("__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${(
            path ?? parent_path
          )?.replaceAll("/", "__")}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } if (path_type == "app") {
        return `${path}.app/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 731 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing ${path_type} ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      let repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const azureMatch = repo_url.match(/AZURE_DEVOPS_TOKEN\((?<url>.+)\)/);
    
      if (azureMatch) {
        console.log(
          "Requires Azure DevOps service account access token, requesting..."
        );
        const azureResource = await wmillclient.getResource(azureMatch.groups.url);
    
        const response = await fetch(
          `https://login.microsoftonline.com/${azureResource.azureTenantId}/oauth2/token`,
          {
            method: "POST",
            body: new URLSearchParams({
              client_id: azureResource.azureClientId,
              client_secret: azureResource.azureClientSecret,
              grant_type: "client_credentials",
              resource: "499b84ac-1321-427f-aa17-267ca6975798/.default",
            }),
          }
        );
    
        const { access_token } = await response.json();
    
        repo_url = repo_url.replace(azureMatch[0], access_token);
      }
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${(path ?? parent_path)
            ?.split("/")
            .slice(0, 2)
            .join("__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${(
            path ?? parent_path
          )?.replaceAll("/", "__")}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } if (path_type == "app") {
        return `${path}.app/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 731 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing ${path_type} ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      let repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const azureMatch = repo_url.match(/AZURE_DEVOPS_TOKEN\((?<url>.+)\)/);
    
      if (azureMatch) {
        console.log(
          "Requires Azure DevOps service account access token, requesting..."
        );
        const azureResource = await wmillclient.getResource(azureMatch.groups.url);
    
        const response = await fetch(
          `https://login.microsoftonline.com/${azureResource.azureTenantId}/oauth2/token`,
          {
            method: "POST",
            body: new URLSearchParams({
              client_id: azureResource.azureClientId,
              client_secret: azureResource.azureClientSecret,
              grant_type: "client_credentials",
              resource: "499b84ac-1321-427f-aa17-267ca6975798/.default",
            }),
          }
        );
    
        const { access_token } = await response.json();
    
        repo_url = repo_url.replace(azureMatch[0], access_token);
      }
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${(path ?? parent_path)
            ?.split("/")
            .slice(0, 2)
            .join("__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${(
            path ?? parent_path
          )?.replaceAll("/", "__")}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } if (path_type == "app") {
        return `${path}.app/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 752 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing ${path_type} ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      let repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const azureMatch = repo_url.match(/AZURE_DEVOPS_TOKEN\((?<url>.+)\)/);
    
      if (azureMatch) {
        console.log(
          "Requires Azure DevOps service account access token, requesting..."
        );
        const azureResource = await wmillclient.getResource(azureMatch.groups.url);
    
        const response = await fetch(
          `https://login.microsoftonline.com/${azureResource.azureTenantId}/oauth2/token`,
          {
            method: "POST",
            body: new URLSearchParams({
              client_id: azureResource.azureClientId,
              client_secret: azureResource.azureClientSecret,
              grant_type: "client_credentials",
              resource: "499b84ac-1321-427f-aa17-267ca6975798/.default",
            }),
          }
        );
    
        const { access_token } = await response.json();
    
        repo_url = repo_url.replace(azureMatch[0], access_token);
      }
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${(path ?? parent_path)
            ?.split("/")
            .slice(0, 2)
            .join("__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${(
            path ?? parent_path
          )?.replaceAll("/", "__")}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } if (path_type == "app") {
        return `${path}.app/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 753 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing ${path_type} ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      let repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const azureMatch = repo_url.match(/AZURE_DEVOPS_TOKEN\((?<url>.+)\)/);
    
      if (azureMatch) {
        console.log(
          "Requires Azure DevOps service account access token, requesting..."
        );
        const azureResource = await wmillclient.getResource(azureMatch.groups.url);
    
        const response = await fetch(
          `https://login.microsoftonline.com/${azureResource.azureTenantId}/oauth2/token`,
          {
            method: "POST",
            body: new URLSearchParams({
              client_id: azureResource.azureClientId,
              client_secret: azureResource.azureClientSecret,
              grant_type: "client_credentials",
              resource: "499b84ac-1321-427f-aa17-267ca6975798/.default",
            }),
          }
        );
    
        const { access_token } = await response.json();
    
        repo_url = repo_url.replace(azureMatch[0], access_token);
      }
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${(path ?? parent_path)
            ?.split("/")
            .slice(0, 2)
            .join("__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${(
            path ?? parent_path
          )?.replaceAll("/", "__")}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } if (path_type == "app") {
        return `${path}.app/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 753 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      let repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const azureMatch = repo_url.match(/AZURE_DEVOPS_TOKEN\((?<url>.+)\)/);
    
      if (azureMatch) {
        console.log(
          "Requires Azure DevOps service account access token, requesting..."
        );
        const azureResource = await wmillclient.getResource(azureMatch.groups.url);
    
        const response = await fetch(
          `https://login.microsoftonline.com/${azureResource.azureTenantId}/oauth2/token`,
          {
            method: "POST",
            body: new URLSearchParams({
              client_id: azureResource.azureClientId,
              client_secret: azureResource.azureClientSecret,
              grant_type: "client_credentials",
              resource: "499b84ac-1321-427f-aa17-267ca6975798/.default",
            }),
          }
        );
    
        const { access_token } = await response.json();
    
        repo_url = repo_url.replace(azureMatch[0], access_token);
      }
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${(path ?? parent_path)
            ?.split("/")
            .slice(0, 2)
            .join("__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${(
            path ?? parent_path
          )?.replaceAll("/", "__")}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 759 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
      group_by_folder = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`,
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
        group_by_folder
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret,
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
      group_by_folder: boolean,
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
    
      const branchName = group_by_folder
        ? `wm_deploy/${workspace_id}/${
          (path ?? parent_path)?.split("/").slice(0, 2).join("__")
        }`
        : `wm_deploy/${workspace_id}/${path_type}/${
          (path ?? parent_path)?.replaceAll(
            "/",
            "__",
          )
        }`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? "",
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? "",
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position;
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(
            " ",
          )
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string,
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean,
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(","),
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 776 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
      const branchName =
        path !== undefined
          ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
          : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll(
              "/",
              "__"
            )}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 790 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-1, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
      const branchName =
        path !== undefined
          ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
          : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll(
              "/",
              "__"
            )}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 790 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-2, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
      const branchName =
        path !== undefined
          ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
          : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll(
              "/",
              "__"
            )}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 790 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-2, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
      const branchName =
        path !== undefined
          ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
          : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll(
              "/",
              "__"
            )}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position < 0) {
        secret_position = nargs.length - 1 + secret_position
      }
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 790 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-2, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean
    ) {
      if (!use_individual_branch || path_type === "user" || path_type === "group") {
        return;
      }
      const branchName =
        path !== undefined
          ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
          : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll(
              "/",
              "__"
            )}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else if (path_type == "user") {
        return `${path}.user.*`;
      } else if (path_type == "group") {
        return `${path}.group.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule"
        | "user"
        | "group",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--include-users",
        "--include-groups",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 800 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`
      );
    
      await wmill_sync_pull(
        path_type,
        workspace_id,
        path,
        parent_path,
        skip_secret
      );
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = ["clone", "--quiet", "--depth", "1"];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(-2, "git", ...args);
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(undefined, "git", "sparse-checkout", "add", subfolder);
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName =
        path !== undefined
          ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
          : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll(
              "/",
              "__"
            )}`;
    
      try {
        await sh_run(undefined, "git", "checkout", branchName);
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`
        );
        try {
          await sh_run(undefined, "git", "checkout", "-b", branchName);
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true"
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? ""
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? ""
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(undefined, "git", "add", `${parent_path}**`);
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(undefined, "git", "diff", "--cached", "--quiet");
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(undefined, "git", "commit", "-m", commit_msg);
        await sh_run(undefined, "git", "push", "--porcelain");
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${args.join(
          " "
        )}' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      path: string
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type:
        | "script"
        | "flow"
        | "app"
        | "folder"
        | "resource"
        | "variable"
        | "resourcetype"
        | "schedule",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--includes",
        includes.join(",")
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "");
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 806 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app" | "folder" | "resource" | "variable" | "resourcetype" | "schedule",
      skip_secret = true,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`,
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path, skip_secret);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app" | "folder" | "resource" | "variable" | "resourcetype" | "schedule",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined
        ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${
          parent_path.replaceAll("/", "__")
        }`;
    
      try {
        await sh_run(
          undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? '',
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? '',
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type: "script" | "flow" | "app" | "folder" | "resource" | "variable" | "resourcetype" | "schedule",
      path: string,
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type: "script" | "flow" | "app" | "folder" | "resource" | "variable" | "resourcetype" | "schedule",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
      skip_secret: boolean,
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        skip_secret ? "--skip-secrets" : "",
        "--include-schedules",
        "--includes",
        includes.join(","),
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd = cmd.filter((elt) => elt !== "")
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 829 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app" | "folder" | "resource" | "variable" | "resourcetype" | "schedule",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`,
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app" | "folder" | "resource" | "variable" | "resourcetype" | "schedule",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined
        ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${
          parent_path.replaceAll("/", "__")
        }`;
    
      try {
        await sh_run(
          undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL") ?? '',
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME") ?? '',
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      const nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type: "script" | "flow" | "app" | "folder" | "resource" | "variable" | "resourcetype" | "schedule",
      path: string,
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else if (path_type == "resourcetype") {
        return `${path}.resource-type.*`;
      } else if (path_type == "resource") {
        return `${path}.resource.*`;
      } else if (path_type == "variable") {
        return `${path}.variable.*`;
      } else if (path_type == "schedule") {
        return `${path}.schedule.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type: "script" | "flow" | "app" | "folder" | "resource" | "variable" | "resourcetype" | "schedule",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
    ) {
      const includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--include-schedules",
        "--includes",
        includes.join(","),
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      const cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 829 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app" | "folder",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`,
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined
        ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${
          parent_path.replaceAll("/", "__")
        }`;
    
      try {
        await sh_run(
          undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      let nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type: "script" | "flow" | "app" | "folder",
      path: string,
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type: "script" | "flow" | "app" | "folder",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
    ) {
      let includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs;
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--include-schedules",
        "--includes",
        includes.join(","),
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      let cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 829 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app" | "folder",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`,
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined
        ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${
          parent_path.replaceAll("/", "__")
        }`;
    
      try {
        await sh_run(
          undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      let nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type: "script" | "flow" | "app" | "folder",
      path: string,
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type: "script" | "flow" | "app" | "folder",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
    ) {
      let includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs;
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--includes",
        includes.join(","),
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      let cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 829 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app" | "folder",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(
        `Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`,
      );
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(
        workspace_id,
        path_type,
        path,
        parent_path,
        use_individual_branch,
      );
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined
        ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}`
        : `wm_deploy/${workspace_id}/${path_type}/${
          parent_path.replaceAll("/", "__")
        }`;
    
      try {
        await sh_run(
          undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
    ) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`);
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`);
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(
      secret_position: number | undefined,
      cmd: string,
      ...args: string[]
    ) {
      let nargs = secret_position != undefined ? args.slice() : args;
      if (secret_position != undefined) {
        nargs[secret_position] = "***";
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(
      path_type: "script" | "flow" | "app" | "folder",
      path: string,
    ) {
      if (path_type == "flow") {
        return `${path}.flow/*`;
      } else if (path_type == "folder") {
        return `${path}/folder.meta.*`;
      } else {
        return `${path}.*`;
      }
    }
    async function wmill_sync_pull(
      path_type: "script" | "flow" | "app" | "folder",
      workspace_id: string,
      path: string | undefined,
      parent_path: string | undefined,
    ) {
      let includes = [];
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path));
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path));
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs;
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes",
        includes.join(","),
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      let cmd2 = cmd.slice();
      cmd2[secret_position] = "***";
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 832 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
        undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`)
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(secret_position: number | undefined, cmd: string, ...args: string[]) {
      let nargs = secret_position != undefined ? args.slice() : args
      if (secret_position != undefined) {
        nargs[secret_position] = '***'
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(","),
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      let cmd2 = cmd.slice()
      cmd2[secret_position] = '***'
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
        undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`)
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(secret_position: number | undefined, cmd: string, ...args: string[]) {
      let nargs = secret_position != undefined ? args.slice() : args
      if (secret_position != undefined) {
        nargs[secret_position] = '***'
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(","),
        3
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      let cmd2 = cmd.slice()
      cmd2[secret_position] = '***'
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
        undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`)
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(secret_position: number | undefined, cmd: string, ...args: string[]) {
      let nargs = secret_position != undefined ? args.slice() : args
      if (secret_position != undefined) {
        nargs[secret_position] = '***'
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(","),
        3
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      let cmd2 = cmd.slice()
      cmd2[secret_position] = '***'
      console.log(`Running 'wmill ${cmd2.join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
        undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`)
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(secret_position: number | undefined, cmd: string, ...args: string[]) {
      let nargs = secret_position != undefined ? args.slice() : args
      if (secret_position != undefined) {
        nargs[secret_position] = '***'
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(","),
        3
      );
    }
    
    async function wmill_run(secret_position: number, ...cmd: string[]) {
      cmd[secret_position] = '***'
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
        undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`)
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(secret_position: number | undefined, cmd: string, ...args: string[]) {
      let nargs = secret_position != undefined ? args.slice() : args
      if (secret_position != undefined) {
        nargs[secret_position] = '***'
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        6,
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? ""
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        3,
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(","),
        3
      );
    }
    
    async function wmill_run(...cmd: string[], secret_position: number) {
      cmd[secret_position] = '***'
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
        undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`)
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(secret_position: number | undefined, cmd: string, ...args: string[]) {
      let nargs = secret_position != undefined ? args.slice() : args
      if (secret_position != undefined) {
        nargs[secret_position] = '***'
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        "workspace",
        "add",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(","),
        3
      );
    }
    
    async function wmill_run(...cmd: string[]) {
      cmd[3] = '***'
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        -2,
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          undefined,
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
        undefined,
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            undefined,
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            undefined,
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        undefined,
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        undefined,
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}**, ${e}`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            undefined,
            "git",
            "add",
            `${parent_path}**`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`)
        }
      }
      try {
        await sh_run(
          undefined,
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          undefined,
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          undefined,
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(secret_position: number | undefined, cmd: string, ...args: string[]) {
      let nargs = secret_position != undefined ? args.slice() : args
      if (secret_position != undefined) {
        nargs[secret_position] = '***'
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(","),
        3
      );
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${path}*, ${e}`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch (e) {
          console.log(`Unable to stage files matching ${parent_path}, ${e}`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[], secret_position?: number) {
      let nargs = secret_position != undefined ? args.slice() : args
      if (secret_position != undefined) {
        nargs[secret_position] = '***'
      }
      console.log(`Running '${cmd} ${nargs.join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(","),
        3
      );
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path_type, workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function regexFromPath(path_type: "script" | "flow" | "app", path: string ) {
        if (path_type == 'flow') {
            return `${path}.flow/*`
        } else {
            return `${path}.*`
        }
    }
    async function wmill_sync_pull(path_type: "script" | "flow" | "app", workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(regexFromPath(path_type, path))
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(regexFromPath(path_type, parent_path))
      }
    
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(",")
      );
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 833 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(`${path}*`)
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(`${parent_path}*`)
      }
    
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--includes", 
        includes.join(",")
      );
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 841 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(`${path}*`)
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(`${parent_path}*`)
      }
    
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--excludes",
        "**",
        "--includes", 
        includes.join(",")
      );
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 841 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let includes = []
      if (path !== undefined && path !== null && path !== "") {
        includes.push(`${path}*`)
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        includes.push(`${parent_path}*`)
      }
    
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      let includesArgs
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
        "--excludes"
        "**"
        "--includes", 
        includes.join(",")
      );
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 841 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let wmillignore = `*\n`
      if (path !== undefined && path !== null && path !== "") {
        wmillignore = `${wmillignore}\n!${path}*\n`
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        wmillignore = `${wmillignore}\n!${parent_path}*\n`
      }
      await Deno.writeTextFile(".wmillignore", wmillignore);
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 841 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let wmillignore = `*\n`
      if (path !== undefined && path !== null && path !== "") {
        wmillignore = `${wmillignore}\n!${path}*\n`
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        wmillignore = `${wmillignore}\n!${parent_path}*\n`
      }
      await Deno.writeTextFile(".wmillignore", wmillignore);
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 846 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let wmillignore = `*\n`
      if (path !== undefined && path !== null && path !== "") {
        wmillignore = `${wmillignore}\n!${path}*\n`
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        wmillignore = `${wmillignore}\n!${parent_path}*\n`
      }
      await Deno.writeTextFile(".wmillignore", wmillignore);
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by rubenfiszel 846 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      workspace_id: string,
      repo_url_resource_path: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(workspace_id, path_type, path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(workspace_id, path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      workspace_id: string,
      path_type: "script" | "flow" | "app",
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${workspace_id}/${path_type}/${path.replaceAll("/", "__")}` : `wm_deploy/${workspace_id}/${path_type}/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(workspace_id: string, path: string | undefined, parent_path: string | undefined) {
      let wmillignore = `*\n`
      if (path !== undefined && path !== null && path !== "") {
        wmillignore = `${wmillignore}\n!${path}*\n`
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        wmillignore = `${wmillignore}\n!${parent_path}*\n`
      }
      await Deno.writeTextFile(".wmillignore", wmillignore);
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        workspace_id,
        workspace_id,
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        workspace_id,
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 858 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      path: string | undefined,
      parent_path: string | undefined,
      commit_msg: string,
      use_individual_branch = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path ?? ""} with parent ${parent_path ?? ""}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(path, parent_path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path, parent_path);
    
      await git_push(path, parent_path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      path: string | undefined,
      parent_path: string | undefined,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = path !== undefined ? `wm_deploy/${path.replaceAll("/", "__")}` : `wm_deploy/${parent_path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string | undefined, parent_path: string | undefined, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      if (path !== undefined && path !== null && path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${path}*`)
        }
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        try {
          await sh_run(
            "git",
            "add",
            `${parent_path}*`,
          );
        } catch {
          console.log(`Unable to stage files matching ${parent_path}*`)
        }
      }
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(path: string | undefined, parent_path: string | undefined) {
      let wmillignore = `*\n`
      if (path !== undefined && path !== null && path !== "") {
        wmillignore = `${wmillignore}\n!${path}*\n`
      }
      if (parent_path !== undefined && parent_path !== null && parent_path !== "") {
        wmillignore = `${wmillignore}\n!${parent_path}*\n`
      }
      await Deno.writeTextFile(".wmillignore", wmillignore);
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        Deno.env.get("WM_WORKSPACE"),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 861 days ago

  • deno
    import * as wmillclient from "npm:[email protected]";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      path: string,
      commit_msg: string,
      use_individual_branch: boolean = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path);
    
      await git_push(path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      path: string,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = `wm_deploy/${path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      await sh_run(
        "git",
        "add",
        `${path}*`,
      );
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${path}`);
      await wmill_run(
        "version",
      );
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        Deno.env.get("WM_WORKSPACE"),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 866 days ago

  • deno
    import * as wmillclient from "npm:windmill-client@1";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      path: string,
      commit_msg: string,
      use_individual_branch: boolean = false,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path}`);
    
      const repo_name = await git_clone(cwd, repo_resource, use_individual_branch);
      await move_to_git_branch(path, use_individual_branch);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(
        `Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`,
      );
    
      await wmill_sync_pull(path);
    
      await git_push(path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(
      cwd: string,
      repo_resource: any,
      use_individual_branch: boolean,
    ): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (use_individual_branch) {
        args.push("--no-single-branch"); // needed in case the asset branch already exists in the repo
      }
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`,
        );
        throw err;
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(
          `Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`,
        );
        throw err;
      }
    
      return repo_name;
    }
    
    async function move_to_git_branch(
      path: string,
      use_individual_branch: boolean,
    ) {
      if (!use_individual_branch) {
        return;
      }
      const branchName = `wm_deploy/${path.replaceAll("/", "__")}`;
    
      try {
        await sh_run(
          "git",
          "checkout",
          branchName,
        );
      } catch (err) {
        console.log(
          `Error checking out branch ${branchName}. It is possible it doesn't exist yet, tentatively creating it... Error was:\n${err}`,
        );
        try {
          await sh_run(
            "git",
            "checkout",
            "-b",
            branchName,
          );
          await sh_run(
            "git",
            "config",
            "--add",
            "--bool",
            "push.autoSetupRemote",
            "true",
          );
        } catch (err) {
          console.log(
            `Error checking out branch '${branchName}'. Error was:\n${err}`,
          );
          throw err;
        }
      }
      console.log(`Successfully switched to branch ${branchName}`);
    }
    
    async function git_push(path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      await sh_run(
        "git",
        "add",
        `${path}*`,
      );
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`);
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout));
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr));
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`;
        throw err;
      }
      console.log("Command successfully executed");
    }
    
    async function wmill_sync_pull(path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${path}`);
      await wmill_run(
        "version",
      );
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        Deno.env.get("WM_WORKSPACE"),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`);
      await wmill.parse(cmd);
      console.log("Command successfully executed");
    }
    

    Submitted by hugo697 867 days ago

  • deno
    import * as wmillclient from "npm:windmill-client@1";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      path: string,
      commit_msg: string,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path}`);
    
      const repo_name = await git_clone(cwd, repo_resource);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(`Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`);
    
      await wmill_sync_pull(path);
    
      await git_push(path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(cwd: string, repo_resource: any): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      try {
        Deno.chdir(`${cwd}/${repo_name}`);
      } catch (err) {
        console.log(`Error changing directory to '${cwd}/${repo_name}'. Error was:\n${err}`)
        throw err
      }
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      try {
        Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
      } catch (err) {
        console.log(`Error changing directory to '${cwd}/${repo_name}/${subfolder}'. Error was:\n${err}`)
        throw err
      }
    
      return repo_name;
    }
    
    async function git_push(path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      await sh_run(
        "git",
        "add",
        `${path}*`,
      );
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
          "--porcelain"
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      console.log(`Running '${cmd} ${args.slice(0, 1).join(" ")} ...'`)
      const command = new Deno.Command(cmd, {
        args: args,
      });
    
      const { code, stdout, stderr } = await command.output();
      if (stdout.length > 0) {
        console.log(new TextDecoder().decode(stdout))
      }
      if (stderr.length > 0) {
        console.log(new TextDecoder().decode(stderr))
      }
      if (code !== 0) {
        const err = `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}.`
        throw err;
      }
      console.log("Command successfully executed")
    }
    
    async function wmill_sync_pull(path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${path}`);
      await wmill_run(
        "version",
      );
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        Deno.env.get("WM_WORKSPACE"),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      console.log(`Running 'wmill ${cmd.slice(0, 1).join(" ")} ...'`)
      await wmill.parse(cmd);
      console.log("Command successfully executed")
    }
    

    Submitted by hugo697 891 days ago

  • deno
    import * as wmillclient from "npm:windmill-client@1";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      path: string,
      commit_msg: string,
    ) {
      const repo_resource = await wmillclient.getResource(repo_url_resource_path);
    
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path}`);
    
      const repo_name = await git_clone(cwd, repo_resource);
    
      const subfolder = repo_resource.folder ?? "";
      const branch_or_default = repo_resource.branch ?? "<DEFAULT>";
      console.log(`Pushing to repository ${repo_name} in subfolder ${subfolder} on branch ${branch_or_default}`);
    
      await wmill_sync_pull(path);
    
      await git_push(path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(cwd: string, repo_resource: any): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = repo_resource.url;
      const subfolder = repo_resource.folder ?? "";
      const branch = repo_resource.branch ?? "";
      const repo_name = basename(repo_url, ".git");
    
      const args = [
        "clone",
        "--quiet",
        "--depth",
        "1",
      ];
      if (subfolder !== "") {
        args.push("--sparse");
      }
      if (branch !== "") {
        args.push("--branch");
        args.push(branch);
      }
      args.push(repo_url);
      args.push(repo_name);
      await sh_run(
        "git",
        ...args,
      );
    
      Deno.chdir(`${cwd}/${repo_name}`);
      if (subfolder !== "") {
        await sh_run(
          "git",
          "sparse-checkout",
          "add",
          subfolder,
        );
      }
      Deno.chdir(`${cwd}/${repo_name}/${subfolder}`);
    
      return repo_name;
    }
    
    async function git_push(path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      await sh_run(
        "git",
        "add",
        `${path}*`,
      );
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      // console.log(`Running '${cmd} ${args.join(" ")}'`)
      const command = new Deno.Command(cmd, {
        args: args,
      });
      const { code, stdout: _stdout, stderr: _stderr } = await command.output();
    
      if (code !== 0) {
        throw `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}`;
      }
    }
    
    async function wmill_sync_pull(path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${path}`);
      await wmill_run(
        "version",
      );
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        Deno.env.get("WM_WORKSPACE"),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      // console.log(`Running '${cmd.join(" ")}'`)
      await wmill.parse(cmd);
    }
    

    Submitted by hugo697 891 days ago

  • deno
    import * as wmillclient from "npm:windmill-client@1";
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      path: string,
      commit_msg: string,
    ) {
      const cwd = Deno.cwd();
      Deno.env.set("HOME", ".");
      console.log(`Syncing script/flow/app ${path}`);
    
      const repo_name = await git_clone(repo_url_resource_path);
    
      Deno.chdir(`${cwd}/${repo_name}`);
      console.log(`Pushing to repository ${repo_name}`);
    
      await wmill_sync_pull(path);
    
      await git_push(path, commit_msg);
    
      console.log("Finished syncing");
      Deno.chdir(`${cwd}`);
    }
    
    async function git_clone(repo_resource_path: string): Promise<string> {
      // TODO: handle private SSH keys as well
      const repo_url = (await wmillclient.getResource(repo_resource_path)).url;
      const repo_name = basename(repo_url, ".git");
    
      await sh_run(
        "git",
        "clone",
        "--quiet",
        "--depth",
        "1",
        // TODO: We could maybe use --sparse here to make the clone more lightweight
        // TODO: It will use the default branch - we could add the branch name to the resource if needed
        repo_url,
        repo_name,
      );
      return repo_name;
    }
    
    async function git_push(path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get("WM_EMAIL"),
      );
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get("WM_USERNAME"),
      );
      await sh_run(
        "git",
        "add",
        `${path}*`,
      );
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet",
        );
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg,
        );
        await sh_run(
          "git",
          "push",
        );
        return;
      }
      console.log("No changes detected, nothing to commit. Returning...");
    }
    
    async function sh_run(cmd: string, ...args: string[]) {
      // console.log(`Running '${cmd} ${args.join(" ")}'`)
      const command = new Deno.Command(cmd, {
        args: args,
      });
      const { code, stdout: _stdout, stderr: _stderr } = await command.output();
    
      if (code !== 0) {
        throw `SH command '${cmd} ${
          args.join(" ")
        }' returned with a non-zero status ${code}`;
      }
    }
    
    async function wmill_sync_pull(path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${path}`);
      await wmill_run(
        "version",
      );
      console.log("Adding Windmill workspace");
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("WM_WORKSPACE"),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
      );
      console.log("Pulling workspace into git repo");
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? "",
        "--workspace",
        Deno.env.get("WM_WORKSPACE"),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      );
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      // console.log(`Running '${cmd.join(" ")}'`)
      await wmill.parse(cmd);
    }
    

    Submitted by hugo697 895 days ago

  • deno
    
    import * as wmillclient from "npm:windmill-client@1"
    import wmill from "https://deno.land/x/[email protected]/main.ts"
    import { basename } from "https://deno.land/[email protected]/path/mod.ts"
    
    export async function main(
      repo_url_resource_path: string,
      path: string,
      commit_msg: string,
    ) {
      let cwd = Deno.cwd()
      Deno.env.set("HOME", ".")
      console.log(`Syncing script/flow/app ${path}`)
    
      let repo_name = await git_clone(repo_url_resource_path)
    
      Deno.chdir(`${cwd}/${repo_name}`)
      console.log(`Pushing to repository ${repo_name}`)
    
      await wmill_sync_pull(path)
    
      await git_push(path, commit_msg)
    
      console.log("Finished syncing")
      Deno.chdir(`${cwd}`)
    }
    
    async function git_clone(repo_resource_path: string): string {
      // TODO: handle private SSH keys as well
      let repo_url = (await wmillclient.getResource(repo_resource_path)).url
      let repo_name = basename(repo_url, ".git")
    
      await sh_run(
        "git",
        "clone",
        "--quiet",
        "--depth",
        "1",
        // TODO: We could maybe use --sparse here to make the clone more lightweight
        // TODO: It will use the default branch - we could add the branch name to the resource if needed
        repo_url,
        repo_name
      )
      return repo_name
    }
    
    async function git_push(path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get('WM_EMAIL')
      )
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get('WM_USERNAME')
      )
      await sh_run(
        "git",
        "add",
        `${path}*`
      )
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet"
        )
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg
        )
        await sh_run(
          "git",
          "push"
        )
        return
      }
      console.log("No changes detected, nothing to commit. Returning...")
    }
    
    async function sh_run(...cmd: string[]) {
      // console.log(`Running '${cmd.join(" ")}'`)
      let proc = Deno.run({ 
        cmd: cmd,
      })
      let status = await proc.status()
      if (!status.success) {
        throw `SH command '${cmd.join(" ")}' returned with a non-zero status ${status.code}`
      }
    }
    
    async function wmill_sync_pull(path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${path}`)
      await wmill_run(
        "version"
      )
      console.log("Adding Windmill workspace")
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get('WM_WORKSPACE'),
        Deno.env.get('WM_WORKSPACE'),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? '',
      )
      console.log("Pulling workspace into git repo")
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? '',
        "--workspace",
        Deno.env.get('WM_WORKSPACE'),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      )
      await Deno.remove(".wmillignore")
    }
    
    async function wmill_run(...cmd: string[]) {
      // console.log(`Running '${cmd.join(" ")}'`)
      await wmill.parse(cmd)
    }
    

    Submitted by hugo697 897 days ago

  • deno
    
    import * as wmillclient from "npm:windmill-client@1"
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      path: string,
      commit_msg: string,
    ) {
      let cwd = Deno.cwd();
      console.log(`Syncing script/flow/app ${path}`)
    
      let repo_name = await git_clone(repo_url_resource_path)
    
      Deno.chdir(`${cwd}/${repo_name}`);
      console.log(`Pushing to repository ${repo_name}`)
    
      await wmill_sync_pull(path)
    
      await git_push(path, commit_msg)
    
      console.log("Finished syncing")
      Deno.chdir(`${cwd}`)
    }
    
    async function git_clone(repo_resource_path: string): string {
      // TODO: handle private SSH keys as well
      let repo_url = (await wmillclient.getResource(repo_resource_path)).url
      let repo_name = basename(repo_url, ".git")
    
      await sh_run(
        "git",
        "clone",
        "--quiet",
        "--depth",
        "1",
        // TODO: We could maybe use --sparse here to make the clone more lightweight
        // TODO: It will use the default branch - we could add the branch name to the resource if needed
        repo_url,
        repo_name
      )
      return repo_name
    }
    
    async function git_push(path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get('WM_EMAIL')
      )
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get('WM_USERNAME')
      )
      await sh_run(
        "git",
        "add",
        `${path}*`
      )
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet"
        )
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg
        )
        await sh_run(
          "git",
          "push"
        )
        return
      }
      console.log("No changes detected, nothing to commit. Returning...")
    }
    
    async function sh_run(...cmd: string[]) {
      // console.log(`Running '${cmd.join(" ")}'`)
      let proc = Deno.run({ 
        cmd: cmd,
      })
      let status = await proc.status()
      if (!status.success) {
        throw `SH command '${cmd.join(" ")}' returned with a non-zero status ${status.code}`
      }
    }
    
    async function wmill_sync_pull(path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${path}`);
      await wmill_run(
        "version"
      );
      console.log("Adding Windmill workspace")
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get('WM_WORKSPACE'),
        Deno.env.get('WM_WORKSPACE'),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? '',
      );
      console.log("Pulling workspace into git repo")
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? '',
        "--workspace",
        Deno.env.get('WM_WORKSPACE'),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      )
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      await wmill.parse(cmd);
    }
    

    Submitted by hugo697 902 days ago

  • deno
    
    import * as wmillclient from "npm:windmill-client@1"
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      path: string,
      commit_msg: string,
    ) {
      let cwd = Deno.cwd();
      console.log(`Syncing script/flow/app ${path}`)
    
      let repo_name = await git_clone(repo_url_resource_path)
    
      Deno.chdir(`${cwd}/${repo_name}`);
      console.log(`Pushing to repository ${repo_name}`)
    
      await wmill_sync_pull(path)
    
      await git_push(path, commit_msg)
    
      console.log("Finished syncing")
      Deno.chdir(`${cwd}`)
    }
    
    async function git_clone(repo_resource_path: string): string {
      // TODO: handle private SSH keys as well
      let repo_url = (await wmillclient.getResource(repo_resource_path)).url
      let repo_name = basename(repo_url, ".git")
    
      await sh_run(
        "git",
        "clone",
        "--quiet",
        "--depth",
        "1",
        // we could use --sparse here
        // Will use the default branch - we could askl the user to use a custom branch instead
        repo_url,
        repo_name
      )
      return repo_name
    }
    
    async function git_push(path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get('WM_EMAIL')
      )
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get('WM_USERNAME')
      )
      await sh_run(
        "git",
        "add",
        `${path}*`
      )
      try {
        await sh_run(
          "git",
          "diff",
          "--cached",
          "--quiet"
        )
      } catch {
        // git diff returns exit-code = 1 when there's at least on staged changes
        await sh_run(
          "git",
          "commit",
          "-m",
          commit_msg
        )
        await sh_run(
          "git",
          "push"
        )
        return
      }
      console.log("No changes detected, nothing to commit. Returning...")
    }
    
    async function sh_run(...cmd: string[]) {
      // console.log(`Running '${cmd.join(" ")}'`)
      let proc = Deno.run({ 
        cmd: cmd,
      })
      let status = await proc.status()
      if (!status.success) {
        throw `SH command '${cmd.join(" ")}' returned with a non-zero status ${status.code}`
      }
    }
    
    async function wmill_sync_pull(path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${path}`);
      await wmill_run(
        "version"
      );
      console.log("Adding Windmill workspace")
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get('WM_WORKSPACE'),
        Deno.env.get('WM_WORKSPACE'),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? '',
      );
      console.log("Pulling workspace into git repo")
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? '',
        "--workspace",
        Deno.env.get('WM_WORKSPACE'),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      )
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      await wmill.parse(cmd);
    }
    

    Submitted by hugo697 902 days ago

  • deno
    
    import * as wmillclient from "npm:windmill-client@1"
    import wmill from "https://deno.land/x/[email protected]/main.ts";
    import { basename } from "https://deno.land/[email protected]/path/mod.ts";
    
    export async function main(
      repo_url_resource_path: string,
      script_path: string,
      commit_msg: string,
    ) {
      let cwd = Deno.cwd();
      console.log(`Syncing script ${script_path}`)
    
      let repo_name = await git_clone(repo_url_resource_path)
    
      Deno.chdir(`${cwd}/${repo_name}`);
      console.log(`Pushing to repository ${repo_name}`)
    
      await wmill_sync_pull(script_path)
    
      await git_push(script_path, commit_msg)
    
      console.log("Finished syncing")
      Deno.chdir(`${cwd}`)
    }
    
    async function git_clone(repo_resource_path: string): string {
      // TODO: handle private SSH keys as well
      let repo_url = (await wmillclient.getResource(repo_resource_path)).url
      let repo_name = basename(repo_url, ".git")
    
      await sh_run(
        "git",
        "clone",
        "--quiet",
        "--depth",
        "1",
        // TODO: We could maybe use --sparse here to make the clone more lightweight
        // TODO: Will use the default branch - we could add the branch name to the resource if needed
        repo_url,
        repo_name
      )
      return repo_name
    }
    
    async function git_push(script_path: string, commit_msg: string) {
      await sh_run(
        "git",
        "config",
        "user.email",
        Deno.env.get('WM_EMAIL')
      )
      await sh_run(
        "git",
        "config",
        "user.name",
        Deno.env.get('WM_USERNAME')
      )
      await sh_run(
        "git",
        "add",
        `${script_path}*`
      )
      await sh_run(
        "git",
        "commit",
        "--allow-empty",
        "-m",
        commit_msg
      )
      await sh_run(
        "git",
        "push"
      )
    }
    
    async function sh_run(...cmd: string[]) {
      // console.log(`Running '${cmd.join(" ")}'`)
      let proc = Deno.run({ 
        cmd: cmd,
      })
      let status = await proc.status()
      if (!status.success) {
        throw `SH command '${cmd.join(" ")}' returned with a non-zero status ${status.code}`
      }
    }
    
    async function wmill_sync_pull(script_path: string) {
      await Deno.writeTextFile(".wmillignore", `*\n!${script_path}`);
      await wmill_run(
        "version"
      );
      console.log("Adding Windmill workspace")
      await wmill_run(
        "workspace",
        "add",
        Deno.env.get('WM_WORKSPACE'),
        Deno.env.get('WM_WORKSPACE'),
        Deno.env.get("BASE_INTERNAL_URL") + "/",
        "--token",
        Deno.env.get("WM_TOKEN") ?? '',
      );
      console.log("Pulling workspace into git repo")
      await wmill_run(
        "sync",
        "pull",
        "--token",
        Deno.env.get("WM_TOKEN") ?? '',
        "--workspace",
        Deno.env.get('WM_WORKSPACE'),
        "--yes",
        "--raw",
        "--skip-variables",
        "--skip-secrets",
        "--skip-resources",
      )
      await Deno.remove(".wmillignore");
    }
    
    async function wmill_run(...cmd: string[]) {
      await wmill.parse(cmd);
    }

    Submitted by hugo697 902 days ago