Hackernoon logoCloudy with a Chance of Git Pulls: Automated Weather Forecasts With GitHub Actions by@woodrock

Cloudy with a Chance of Git Pulls: Automated Weather Forecasts With GitHub Actions

Author profile picture

@woodrockJesse Wood

WIP: Software Engineer

This tutorial covers creating a custom GitHub Action to generate automated Weather Forecasts as seen below (and [here]). It relies on the Open Weather API and Nodejs. Once you understand the basic steps involves here, you will be able to apply them to automate all nature of things.


Clouds: 75%
Humidity: 77%
Wind: 8.75 m/s
Pressure: 1001hpa


Actions are often an important part of the continuous integration and development process. As developers, we enjoy being as lazy as possible. We can do this, by automating tedious, dull, and repetitive tasks. This reduces the human resources cost and improves the efficiency of your work.

The more you can automate in your day to day life, the more time you have to spend on what is meaningful. My boss once told me that I am the laziest worker he had ever seen, but he said he meant that as the highest form of praise to describe how efficiently I worked. Or perhaps, he has just trying to be nice.

The repository relies on four main files:

  • README.md
  • action.yml
  • action.js
  • weather.yml

We will go into detail about the implementation details of each of those below. But these are the basic components required to build our own custom GitHub action.

Setting us Node

We use

to run our action on a virtual server provided by GitHub. For this script to work, we need to create a node project:

Install the necessary packages:

npm i @vercel/ncc node-fetch fs @actions/core

Then append our

to include the following script:

"scripts": {
    "build": "ncc build src/action.js -o dist",

Before pushing this repository to GitHub make sure to include a

file with
in at the root level of your directory:


This ignores the very large and unused directory

, which stores the code for all the libraries we just imported. It is not needed by our GitHub action to run.


An example of a README file for this action is shown below.

# Weather Forecast

Tumeric single-origin coffee taiyaki, literally craft beer enamel pin plaid chia direct trade 90's distillery retro vaporware. PBR&B hexagon blue bottle banh mi mumblecore synth, pitchfork actually vegan church-key bicycle rights iceland occupy street art. Normcore disrupt you probably haven't heard of them, crucifix single-origin coffee cornhole listicle. Distillery iPhone enamel pin direct trade venmo quinoa jianbing four loko bespoke unicorn.

## Forecast
<!-- FEED-START -->
<!-- FEED-END -->

It is the page that is displayed to the user when they first visit the URL for a GitHub repo. It uses the Markdown markup language to produce styled text. The Markdown spec even allows us to include HTML snippets (i.e., divs or comments).

It is important to note, that to avoid security vulnerabilities such as XSS (Cross-Site Scripting), GitHub does not allow JavaScript to embedded into their statically hosted README files. We will come back to why this is important soon.

At the top of this file, we have a title,

# Weather Forecast
, this is similar to the
tag from HTML, where the number of hashes
denotes the weight of the header (i.e.,
, etc ... ). Also worth noting, [Hipster Ipsum](https://hipsum.co/) can be used to create amusing placeholder text as seen above.

We then have an embedded Action's workflow badge. These can be generated by clicking the

tab on the repository. Selecting a workflow, in our case
. Expanding the three dots
option in the top right, and clicking
create status badge
. This automatically generates the embedded HTML necessary to be added to our Markdown file. Programmers love these badges, and adorn them to their repositories as badges of honour, so welcome to the club!

We then have a secondary header for our weather forecast

## Forecast
, followed by an HTML comment. This comment is hidden when viewing the README on the URL, but it is there when we edit the document. Notice the tags
. This let our
script (to be discussed later) know where we want to append our weather forecast. We use these tags so that we do not overwrite the existing content of the README, each time a new forecast is given.


This is the YAML file for our action. It describes the necessary meta-data, such that we can publish it to the GitHub market place, and the inputs that are required for the action to function.

name: "Weather Forecast Action"
description: "Display weather forecast for any area in a project README"
author: "woodrock"

    description: "GitHub token"
    required: true
    description: "Open Weather API Token"
    required: true
    description: "City to get the forecast for"
    required: true

  using: "node12"
  main: "dist/index.js"

Here we have three inputs:

  • CITY

These are environment variables that are used by our scripts. The first two provide access to the APIs, so we can generate the necessary content. The

is automatically generated by the repository, so we do not need to worry about that.


is an API key from the Open Weather API. You will need to register an account for this site, should you wish to recreate this action. Once registered, click on your username on the top right of the navigation bar, then select 'My API Keys'. You can either use the default key provided by your account or create an isolated key, to be used specifically by this application. Copy that key into your clipboard.

Now we need to create a GitHub secret. This is an environment variable stored securely by GitHub so that we don't expose sensitive information, such as our API Key, to the public. Return to the repository. Click

. On the navigation bar to the left, select
. Select
New Repository Secret
, call it
and copy and paste your Open Weather API key as its value.

We specify the city in the

. This is included so that this action can be reused for different locations. Now, it can be used to forecast the weather anywhere in the world, as opposed to hard-coding a city value in our
. Generic solutions in the software are more maintainable as they encourage re-use without the need to refactor.


The script that performs the work is shown below. It is located in the


const fetch = require("node-fetch");
const fs = require("fs");
const core = require("@actions/core");

const FILE_NAME = "./README.md";
const ENCODING = "utf8";
const TAG_OPEN = `<!-- FEED-START -->`;
const TAG_CLOSE = `<!-- FEED-END -->`;

async function fetchWeather() {
  const API_KEY = core.getInput("OPEN_WEATHER_TOKEN");
  const city = core.getInput("CITY");
  const URL = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&mode=html`;
  return fetch(URL)
    .then((response) => response.text())
    .then((html) => html);

async function run() {
  const readme = fs.readFileSync(FILE_NAME, ENCODING);
  const indexBefore = readme.indexOf(TAG_OPEN) + TAG_OPEN.length;
  const indexAfter = readme.indexOf(TAG_CLOSE);
  const before = readme.substring(0, indexBefore);
  const after = readme.substring(indexAfter);
  const input = (await fetchWeather()).replace(/<script.*>.*<\/script>/ims, "");
  const edited = `
  fs.writeFileSync(FILE_NAME, edited.trim());

try {
} catch (error) {

At the top, we import all the packages we need. We use

to make an API call using javascript asynchronous functions.
allows us to perform FileIO operations, such as reading and writing to a
allows us to request access to the repository secrets, our
, and the
environment variable.


method requests the Open Weather API token and performs an API call using
. We use string templating to structure a custom call to this API:

We specify the city and the API key and request that the response from the API in an HTML format so that we can simply embed this into our

. The weather API returns an HTML object, that includes
tags to neatly render the response.

However, as mentioned previously, we cannot embed JavaScript into a static

hosted by GitHub. So instead, we strip the HTML of the
tags and the content inside them. This is done using the

await fetchWeather().replace(/<script.*>.*<\/script>/ims, "")

Then we perform some arithmetic, to find where our

tags are, and append the embedded weather forecast within these tags. Without overwriting any of the existing document outside these tags.

This script must be built by running the following command in your terminal:

npm run build

This ensures that our action a compiled version of our current program.


This is the GitHub Workflow that runs our script. It is located in the


name: "Weather"

    - cron: "*/30 * * * *" # Runs every 30 minutes

    name: "Update Blogs"
    runs-on: ubuntu-latest
      - name: "πŸ“₯ Fetching Repository Contents"
        uses: actions/checkout@main
      - name: "🌨️ Fetching Weather Forecast"
        uses: ./
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
          CITY: "Wellington, New Zealand"
      - name: "πŸ› οΈ Push changes to GitHub"
            git config --global user.email readme-bot@example.com && git config --global user.name readme-bot;
            git diff --quiet && git diff --staged --quiet || git commit -am '[BOT] Update Readme' && git push;

We use the

so we can trigger our script to be run automatically at certain intervals. We specify that interval using cron. This is a time-based job scheduler from Unix machines. Here
*/30 * * * *
we set the workflow to be run once every 30 minutes, every hour, every month, every day of the week.

Our workflow has three jobs. The first uses

to clone our repository to the virtual machine running the workflow. The second run our script using the
docker image we specified in the
. With the main script being
. We provide access repository secretes, the
, under the
section. We can specify the
of our choice here, in this case, I specify my home city
Wellington, New Zealand

Finally, we push our changes to the repository. The workflow is set to have a GitHub user with the name

. This makes it clear that updates to the
in our repository are being done by a service account, not an actual user. This is an important distinction, for separating intentional changes by users, from automated ones by our GitHub Action. To reinforce this idea we include
in the commit message as well.


And we are done. This is how you build an automated weather forecasting bot using GitHub Actions. The principles learned here can be applied to any other API of your choice; here is a list just to name a few, the possibilities are endless. After completing this tutorial, you should feel comfortable implementing APIs of your own. Each free GitHub account has access to 2,000 Workflow minutes, so don't let them go to waste.


To see the whole thing in action, please check out the original repository, feel free to fork this, and build your amazing Actions.

Previously published at https://woodrock.hashnode.dev/cloudy-with-a-chance-of-git-pulls


Join Hacker Noon

Create your free account to unlock your custom reading experience.