Improve portability
							parent
							
								
									751f431767
								
							
						
					
					
						commit
						610947eefb
					
				@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					import { describe, expect, it } from "bun:test";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    createJSONResponse,
 | 
				
			||||||
 | 
					  execContainer,
 | 
				
			||||||
 | 
					  executeScriptInContainer,
 | 
				
			||||||
 | 
					  findResourceInstance,
 | 
				
			||||||
 | 
					  runContainer,
 | 
				
			||||||
 | 
					  runTerraformApply,
 | 
				
			||||||
 | 
					  runTerraformInit,
 | 
				
			||||||
 | 
					  testRequiredVariables,
 | 
				
			||||||
 | 
					} from "../test";
 | 
				
			||||||
 | 
					import { serve } from "bun";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe("slackme", async () => {
 | 
				
			||||||
 | 
					  await runTerraformInit(import.meta.dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  testRequiredVariables(import.meta.dir, {
 | 
				
			||||||
 | 
					    agent_id: "foo",
 | 
				
			||||||
 | 
					    auth_provider_id: "foo",
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const setupContainer = async (image = "alpine") => {
 | 
				
			||||||
 | 
					    const state = await runTerraformApply(import.meta.dir, {
 | 
				
			||||||
 | 
					      agent_id: "foo",
 | 
				
			||||||
 | 
					      auth_provider_id: "foo",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const instance = findResourceInstance(state, "coder_script");
 | 
				
			||||||
 | 
					    const id = await runContainer(image);
 | 
				
			||||||
 | 
					    return { id, instance };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const writeCoder = async (id: string, script: string) => {
 | 
				
			||||||
 | 
					    const exec = await execContainer(id, [
 | 
				
			||||||
 | 
					      "sh",
 | 
				
			||||||
 | 
					      "-c",
 | 
				
			||||||
 | 
					      `echo '${script}' > /usr/bin/coder && chmod +x /usr/bin/coder`,
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					    expect(exec.exitCode).toBe(0);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it("writes to path as executable", async () => {
 | 
				
			||||||
 | 
					    const { instance, id } = await setupContainer();
 | 
				
			||||||
 | 
					    await writeCoder(id, "exit 0");
 | 
				
			||||||
 | 
					    let exec = await execContainer(id, ["sh", "-c", instance.script]);
 | 
				
			||||||
 | 
					    expect(exec.exitCode).toBe(0);
 | 
				
			||||||
 | 
					    exec = await execContainer(id, ["sh", "-c", "which slackme"]);
 | 
				
			||||||
 | 
					    expect(exec.exitCode).toBe(0);
 | 
				
			||||||
 | 
					    expect(exec.stdout.trim()).toEqual("/usr/bin/slackme");
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it("prints usage with no command", async () => {
 | 
				
			||||||
 | 
					    const { instance, id } = await setupContainer();
 | 
				
			||||||
 | 
					    await writeCoder(id, "echo 👋");
 | 
				
			||||||
 | 
					    let exec = await execContainer(id, ["sh", "-c", instance.script]);
 | 
				
			||||||
 | 
					    expect(exec.exitCode).toBe(0);
 | 
				
			||||||
 | 
					    exec = await execContainer(id, ["sh", "-c", "slackme"]);
 | 
				
			||||||
 | 
					    expect(exec.stdout.trim()).toStartWith(
 | 
				
			||||||
 | 
					      "slackme — Send a Slack notification when a command finishes"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it("displays url when not authenticated", async () => {
 | 
				
			||||||
 | 
					    const { instance, id } = await setupContainer();
 | 
				
			||||||
 | 
					    await writeCoder(id, "echo 'some-url' && exit 1");
 | 
				
			||||||
 | 
					    let exec = await execContainer(id, ["sh", "-c", instance.script]);
 | 
				
			||||||
 | 
					    expect(exec.exitCode).toBe(0);
 | 
				
			||||||
 | 
					    exec = await execContainer(id, ["sh", "-c", "slackme echo test"]);
 | 
				
			||||||
 | 
					    expect(exec.stdout.trim()).toEndWith("some-url");
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it("curls url when authenticated", async () => {
 | 
				
			||||||
 | 
					    let url: URL
 | 
				
			||||||
 | 
					    const fakeSlackHost = serve({
 | 
				
			||||||
 | 
					      fetch: (req) => {
 | 
				
			||||||
 | 
					        url = new URL(req.url);
 | 
				
			||||||
 | 
					        if (url.pathname === "/api/chat.postMessage")
 | 
				
			||||||
 | 
					          return createJSONResponse({
 | 
				
			||||||
 | 
					            ok: true,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        return createJSONResponse({}, 404);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      port: 0,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { instance, id } = await setupContainer("alpine/curl");
 | 
				
			||||||
 | 
					    await writeCoder(id, "echo 'token'");
 | 
				
			||||||
 | 
					    let exec = await execContainer(id, ["sh", "-c", instance.script]);
 | 
				
			||||||
 | 
					    expect(exec.exitCode).toBe(0);
 | 
				
			||||||
 | 
					    exec = await execContainer(id, ["sh", "-c", `SLACK_URL="http://${fakeSlackHost.hostname}:${fakeSlackHost.port}" slackme echo test`]);
 | 
				
			||||||
 | 
					    expect(exec.stdout.trim()).toEndWith("test");
 | 
				
			||||||
 | 
					    expect(url.pathname).toEqual("/api/chat.postMessage");
 | 
				
			||||||
 | 
					    expect(url.searchParams.get("channel")).toEqual("token");
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -1,28 +1,38 @@
 | 
				
			|||||||
#!/usr/bin/env node
 | 
					#!/usr/bin/env sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PROVIDER_ID=${PROVIDER_ID}
 | 
					PROVIDER_ID=${PROVIDER_ID}
 | 
				
			||||||
 | 
					SLACK_MESSAGE="${SLACK_MESSAGE}"
 | 
				
			||||||
 | 
					SLACK_URL=$${SLACK_URL:-https://slack.com}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BOT_TOKEN=\$(coder external-auth access-token $PROVIDER_ID)
 | 
					usage() {
 | 
				
			||||||
 | 
					  cat <<EOF
 | 
				
			||||||
 | 
					slackme — Send a Slack notification when a command finishes
 | 
				
			||||||
 | 
					Usage: slackme <command>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example: slackme npm run long-build
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ $# -eq 0 ]; then
 | 
				
			||||||
 | 
					    usage
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOT_TOKEN=$(coder external-auth access-token $PROVIDER_ID)
 | 
				
			||||||
if [ $? -ne 0 ]; then
 | 
					if [ $? -ne 0 ]; then
 | 
				
			||||||
  echo "Authenticate to run commands in the background:"
 | 
					  printf "Authenticate with Slack to be notified when a command finishes:\n$BOT_TOKEN\n"
 | 
				
			||||||
  # The output contains the URL if failed.
 | 
					 | 
				
			||||||
  echo $BOT_TOKEN
 | 
					 | 
				
			||||||
  exit 1
 | 
					  exit 1
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
USER_ID=\$(coder external-auth access-token $PROVIDER_ID --extra "authed_user.id")
 | 
					USER_ID=$(coder external-auth access-token $PROVIDER_ID --extra "authed_user.id")
 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ $? -ne 0 ]; then
 | 
					if [ $? -ne 0 ]; then
 | 
				
			||||||
  echo "Failed to get authenticated user ID:"
 | 
					  printf "Failed to get authenticated user ID:\n$USER_ID\n"
 | 
				
			||||||
  echo $USER_ID
 | 
					 | 
				
			||||||
  exit 1
 | 
					  exit 1
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo "We'll notify you when done!"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Run all arguments as a command
 | 
					# Run all arguments as a command
 | 
				
			||||||
$@
 | 
					$@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set -e
 | 
				
			||||||
curl --silent -o /dev/null --header "Authorization: Bearer $BOT_TOKEN" \
 | 
					curl --silent -o /dev/null --header "Authorization: Bearer $BOT_TOKEN" \
 | 
				
			||||||
    "https://slack.com/api/chat.postMessage?channel=$USER_ID&text=Your%20command%20finished!&pretty=1"
 | 
					    "$SLACK_URL/api/chat.postMessage?channel=$USER_ID&text=$SLACK_MESSAGE&pretty=1"
 | 
				
			||||||
 | 
				
			|||||||
					Loading…
					
					
				
		Reference in New Issue