This tutorial covers creating a custom GitHub Action to generate automated Weather Forecasts as seen below (and [ ]). It relies on the and Nodejs. Once you understand the basic steps involves here, you will be able to apply them to automate all nature of things. here Open Weather API Wellington °C Clouds: % Humidity: % Wind: m/s Pressure: hpa More.. 18.4 75 77 8.75 1001 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 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. laziest 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: nodejs Install the necessary packages: npm i @vercel/ncc node-fetch fs @actions/core Then append our to include the following script: packages.json "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: .gitignore node_modules node_modules 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. node_modules README.md An example of a README file for this action is shown below. ![ ]( ) 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. # Weather Forecast Weather https://github.com/woodRock/expert-chainsaw/workflows/Weather/badge.svg ## 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 (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. XSS At the top of this file, we have a title, , this is similar to the tag from HTML, where the number of hashes denotes the weight of the header (i.e., equals , equals , etc ... ). Also worth noting, [Hipster Ipsum](https://hipsum.co/) can be used to create amusing placeholder text as seen above. # Weather Forecast <h1> # ## <h2> ### <h3> 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 . 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! Actions weather ... create status badge We then have a secondary header for our weather 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 and . 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. ## Forecast FEED-START FEED-END action.js action.yml 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" inputs: GITHUB_TOKEN: description: "GitHub token" required: true OPEN_WEATHER_TOKEN: description: "Open Weather API Token" required: true CITY: description: "City to get the forecast for" required: true runs: using: "node12" main: "dist/index.js" Here we have three inputs: GITHUB_TOKEN OPEN_WEATHER_TOKEN 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. GITHUB_TOKEN The is an API key from the . 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. OPEN_WEATHER_TOKEN Open Weather API 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 , call it and copy and paste your Open Weather API key as its value. Settings secrets New Repository Secret OPEN_WEATHER_TOKEN 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. weather.yml action.js action.js The script that performs the work is shown below. It is located in the directory. /src fetch = ( ); fs = ( ); core = ( ); FILE_NAME = ; ENCODING = ; TAG_OPEN = ; TAG_CLOSE = ; { API_KEY = core.getInput( ); city = core.getInput( ); URL = ; fetch(URL) .then( response.text()) .then( html); } { readme = fs.readFileSync(FILE_NAME, ENCODING); indexBefore = readme.indexOf(TAG_OPEN) + TAG_OPEN.length; indexAfter = readme.indexOf(TAG_CLOSE); before = readme.substring( , indexBefore); after = readme.substring(indexAfter); input = ( fetchWeather()).replace( s, ); edited = ; fs.writeFileSync(FILE_NAME, edited.trim()); } { run(); } (error) { .log(error); } const require "node-fetch" const require "fs" const require "@actions/core" const "./README.md" const "utf8" const `<!-- FEED-START -->` const `<!-- FEED-END -->` async ( ) function fetchWeather const "OPEN_WEATHER_TOKEN" const "CITY" const `https://api.openweathermap.org/data/2.5/weather?q= &appid= &mode=html` ${city} ${API_KEY} return ( ) => response ( ) => html async ( ) function run const const const const 0 const const await /<script.*>.*<\/script>/im "" const ` ` ${before} ${input} ${after} try catch console 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. fetch fs README.md @actions/core OPEN_WEATHER_TOKEN CITY The 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: fetchWeather() fetch() 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. README <script> 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 method: README <script> replace() fetchWeather().replace( s, ) await /<script.*>.*<\/script>/im "" Then we perform some arithmetic, to find where our and tags are, and append the embedded weather forecast within these tags. Without overwriting any of the existing document outside these tags. FEED-START FEED-END 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. weather.yml This is the GitHub Workflow that runs our script. It is located in the directory. .github/workflows name: "Weather" on: workflow_dispatch: schedule: - cron: "*/30 * * * *" # Runs every 30 minutes jobs: update_blogs: name: "Update Blogs" runs-on: ubuntu-latest steps: - name: "📥 Fetching Repository Contents" uses: actions/checkout@main - name: "🌨️ Fetching Weather Forecast" uses: ./ with: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} OPEN_WEATHER_TOKEN: ${{secrets.OPEN_WEATHER_TOKEN}} CITY: "Wellington, New Zealand" - name: "🛠️ Push changes to GitHub" run: 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 . This is a time-based job scheduler from Unix machines. Here we set the workflow to be run once every 30 minutes, every hour, every month, every day of the week. workflow_dispatch cron */30 * * * * 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 and , under the section. We can specify the of our choice here, in this case, I specify my home city . actions/checkout@main node12 action.yml dist/action.js GITHUB_TOKEN OPEN_WEATHER_TOKEN with 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. readme-bot README [BOT] Conclusion 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; 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. here Appendix To see the whole thing in action, please check out the original , feel free to fork this, and build your amazing Actions. repository Previously published at https://woodrock.hashnode.dev/cloudy-with-a-chance-of-git-pulls