DEV Community

Valeria
Valeria

Posted on • Edited on

Get Magic Eight Ball answers right in your PR or issue comments!

What I built

Magic Eight Ball is a wondrous device that lets a user offload any important decision to a plastic ball. Well, this one you don't even need to shake! I've built a GitHub Action that would allow you to tempt fate and receive answers to the most important questions right in the comments to a PR or an issue!

Category Submission:

Wacky Wildcards

App Link

Try in action

Screenshots

Signs point to a nap first.

My reply is no, but my heart says yes... to pizza.

Description

Action runs on each comment and if it starts with a 🎱 (or another defined prefix) - it will reply with a random answer.

Link to Source Code

GitHub logo ValeriaVG / actions-magic-8-ball

Get Magic ball answers delivered directly to your comments

GitHub Actions: Magic Eight Ball comments

Get Magic ball answers delivered directly to your comments.

How to use

Create an action in .github/workflows:

on:
  issue_comment:
    types: [created]
jobs:
  example_comment_pr:
    runs-on: ubuntu-latest
    name: Magic Eight Ball Comments
    permissions:
        pull-requests: write
        issues: write
    steps:
      - name: Answer
        uses: ValeriaVG/actions-magic-8-ball@v1
Enter fullscreen mode Exit fullscreen mode

Post a comment in PR or and issue starting with "🎱" and get a prediction:

Example response: "🎱 Should I add tests to this repo? - Signs point to a nap first."

With custom prefix

You can also change the prefix to a custom one:

on:
  issue_comment:
    types: [created]
jobs:
  example_comment_pr:
    runs-on: ubuntu-latest
    name: Magic Eight Ball Comments
    permissions:
        pull-requests: write
        issues: write
    steps:
      - name: Answer
        uses: ValeriaVG/actions-magic-8-ball@v1
        with:
          prefix: 'Magic ball, would you please'
Enter fullscreen mode Exit fullscreen mode

Credits

Responses have been generated with Free Research Preview ChatGPT

Can you generate 10 chaotic funny eight ball responses (in json array, of course)?




Permissive License

MIT

Background

I wanted to build something magical, fun, a bit chaotic and over-the-top! I asked a magic eight ball if my fortune cookie idea was any good and it said that magic eight ball was a better one :)

How I built it

I've started with the actual magic eight ball script. The most important part was, of course, to write the answers. I've learned that a classic magic eight ball has 20 answers, but they are so boring...

I wanted something opposite of boring! Therefore I went to ChatGPT and politely asked it to generate some funny responses:

Generate 10 chaotic funny eight ball responses

Of course, I've asked it for an algorithm as well, but it was too plain:

const responses = [
  "It is certain",
  "Without a doubt",
  "Yes – definitely",
  "You may rely on it",
  "As I see it, yes",
  "Most likely",
  "Outlook good",
  "Yes",
  "Signs point to yes",
  "Reply hazy, try again",
  "Better not tell you now",
  "Cannot predict now",
  "Concentrate and ask again",
  "Don't count on it",
  "Outlook not so good",
  "My sources say no",
  "Very doubtful"
];

function generateEightBallResponse() {
  const randomIndex = Math.floor(Math.random() * responses.length);
  return responses[randomIndex];
}

// Example usage
console.log(generateEightBallResponse());
Enter fullscreen mode Exit fullscreen mode

I've asked to rewrite it with crypto.randomBytes, because I sure wanted cryptographically secure random answers (who wouldn't? ):

function generateEightBallResponse() {
  const randomBytes = crypto.randomBytes(1);
  const randomIndex = randomBytes[0] % responses.length;
  return responses[randomIndex];
}
Enter fullscreen mode Exit fullscreen mode

This was a bit better, but one can never have enough magic and so I settled for the following overkill version ( writing it myself this time was faster than trying to explain to an AI what I had in mind ):

function generateEightBallResponse() {
  const randomSize = crypto.randomBytes(1)[0];
  const randomValues = new Uint32Array(randomSize);
  crypto.getRandomValues(randomValues);
  const randomIndex = randomValues[Math.floor(Math.random() * randomSize)] % responses.length;
  return responses[randomIndex];
}
Enter fullscreen mode Exit fullscreen mode

Now that's what I call magic!

Next step was to turn it into an actual GitHub action.

I've looked for some similar actions and it was quite easy to replicate.

I've created an action.yml file in the root of my repository:

name: 'Magic Eight Ball'
branding:
  icon: 'message-circle'
  color: 'gray-dark'
description: 'Replies to a comment with a prediction'
inputs:
  prefix:
    description: 'Prefix that would trigger the response'
    default: '🎱'
    required: false
  GITHUB_TOKEN:
    description: 'Github token of the repository (automatically created by Github)'
    default: ${{ github.token }}
    required: false
runs:
  using: 'node16'
  main: 'lib/index.js'
Enter fullscreen mode Exit fullscreen mode

Added the script to post a comment, using @actions/core and @actions/github packages:

import { context, getOctokit } from "@actions/github";
import { getInput } from "@actions/core";
import generateEightBallResponse from "./generateResponse";

const run = async () => {
  const prefix: string = getInput("prefix");
  const github_token: string = getInput("GITHUB_TOKEN");
  if (
    !context.payload.comment ||
    !context.payload.comment["body"]?.startsWith(prefix)
  ) {
    return;
  }
  const issue_number =
    context.payload.pull_request?.number || context.payload.issue?.number;
  if (!issue_number) {
    return;
  }

  const octokit = getOctokit(github_token);
  const body =
    '> ' + context.payload.comment["body"] + '\n\r' +
    "@" +
    context.payload.comment["user"].login +
    " " +
    generateEightBallResponse();

  await octokit.rest.issues.createComment({
    ...context.repo,
    issue_number,
    body,
  });
};

run();
Enter fullscreen mode Exit fullscreen mode

And created a workflow to test this action in the same repository:

on:
  issue_comment:
    types: [created]
jobs:
  test_8ball:
    name: Magic Eight Ball
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      issues: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Run action from main
        uses: ./
Enter fullscreen mode Exit fullscreen mode

It didn't work on the first try and I've learned about permissions (originally I was missing contents: read and my workflow was failing to checkout the repo).

Then, I've learned that default action runners support node16 at most and I couldn't use crypto.getRandomValues just yet. With a heavy heart I've settled for a little bit less magical random generator (by using crypto.randomBytes twice):

export default function generateEightBallResponse() {
  const randomSize = crypto.randomBytes(1)[0];
  const randomValues = crypto.randomBytes(randomSize);
  const randomIndex =
    randomValues[Math.floor(Math.random() * randomSize)] % responses.length;
  return responses[randomIndex];
}
Enter fullscreen mode Exit fullscreen mode

I could have used a different action and setup whatever version of node I needed, but I wanted the action to be as small and as fast as possible.

I've bundled all code with esbuild into one file and it finally it worked!

In the end I wanted to write some tests, but Magic eight ball told me not to :-P

Top comments (1)

Collapse
 
vulcanwm profile image
Medea

this looks great!