CI Integration

There is more than one way to integrate the radius tracker into your CI pipeline. To keep things simple let’s break down the steps into three stages:

  • Repository Access and Static Analysis

  • Generating the report

  • Publishing the report

Repository Access and Static Analysis

For Radius tracker to analyze your repository it needs read access to the repository. On Github, a common way to provide access is via Personal Access Tokens (PATs); however, for automation and CI/CD processes, it is not recommended. A better approach is using a Github App to manage and grant permissions to CI/CD pipelines.

jobs:
  run-tracker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout this repository
        uses: actions/checkout@v4

The first step is to checkout the repository, note this is not the repository you want to track but the repository containing the global radius configuration. Next step is to retrieve the cache saved from the previous runs:

jobs:
  run-tracker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout this repository
        uses: actions/checkout@v4

      - name: Restore cache for tracker
        id: cache-radius-tracker
        uses: actions/cache/restore@v4        
        with: 
          key: cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}
          path: radius-tracker-cache
          restore-keys: |
            cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}

Note we are using a hash of the configuration file as a key for the cache. In addition we use the restore-keys to get the latest cache. This is because after each run we save a new copy of the cache (github does not allow updating the same cache). The next step is to execute the tracker based on the configuration in the repository we checked out earlier.

      - name: Run the tracker
        run: |
          npx radius-tracker timelines ./radius-tracker.config.js

This will generate a new file usages.sqlite.gz a gzipped sqllite containing the results from the new run and all previous histories. In addition the files under radius-tracker-cache is updated.

Finally we need to update our cache with the new changes and upload the database as an artifact to be used in the next job for generating the report.

      - name: Save cache for tracker
        uses: actions/cache/save@v4        
        with: 
          key: cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}-${{github.run_id}}    
          path: radius-tracker-cache
      
      - name: Upload database artifact
        uses: actions/upload-artifact@v4
        with:
          name: tracker-database
          path: usages.sqlite.gz

Generating the Report

  build-static-site:
    runs-on: ubuntu-latest
    needs: run-tracker
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: tracker-database

      - name: Generate static site
        run: |
          npx radius-tracker report --database usages.sqlite.gz
      
      - name: Upload static site artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: radius-tracker-report/

In the snippet above we are taking advantage of Github pages to publish the report so it is easily accessible and does not require additional hosting. Please note this may not be ideal for all projects as github pages are public for personal or free accounts. The first step downloads the artifact generated in the previous step. To generate static site we simply execute npx radius-tracker report --database usages.sqlite.gz pointing to the database via the --database option.

Finally, we upload the generated folder using Github’s actions/upload-pages-artifact so we can deploy this to github pages in the next job.

Before you can use github pages makes sure it is turned on for the repository. You can follow github’s documentation to set this up before hand.

Publishing the report

  deploy-to-github-pages:
    runs-on: ubuntu-latest
    needs: build-static-site

    permissions:
      contents: read
      pages: write
      id-token: write
    environment:
      name: github-pages
      url: ${{ steps.deploy-pages.outputs.page_url }}
      
    steps:
      - name: Deploy to GitHub Pages
        id: deploy-pages
        uses: actions/deploy-pages@v4

In this example we are publishing to Github pages as mentioned earlier and the final job in the workflow file does that. It is only a single step since the actions/deploy-pages action already does the heavy lifting. The important parts are the permissions and environment . We need to grant the contents, pages and id-token permissions to the job to publish successfully. In the environment section we want to output the link to the published site hence we expose the page_url output.

Putting all the parts together the final workflow file would look like this:

name: run-tracker

on:
  workflow_dispatch:

jobs:
  run-tracker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout this repository
        uses: actions/checkout@v4

      - name: Restore cache for tracker
        id: cache-radius-tracker
        uses: actions/cache/restore@v4        
        with: 
          key: cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}
          path: radius-tracker-cache
          restore-keys: |
            cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}

      - name: Run the tracker
        run: |
          npx radius-tracker timelines ./radius-tracker.config.js

      - name: Save cache for tracker
        uses: actions/cache/save@v4        
        with: 
          key: cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}-${{github.run_id}}    
          path: radius-tracker-cache
      
      - name: Upload database artifact
        uses: actions/upload-artifact@v4
        with:
          name: tracker-database
          path: usages.sqlite.gz
          
          
  build-static-site:
    runs-on: ubuntu-latest
    needs: run-tracker
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: tracker-database

      - name: Generate static site
        run: |
          npx radius-tracker report --database usages.sqlite.gz
      
      - name: Upload static site artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: radius-tracker-report/

  deploy-to-github-pages:
    runs-on: ubuntu-latest
    needs: build-static-site

    permissions:
      contents: read
      pages: write
      id-token: write
    environment:
      name: github-pages
      url: ${{ steps.deploy-pages.outputs.page_url }}
      
    steps:
      - name: Deploy to GitHub Pages
        id: deploy-pages
        uses: actions/deploy-pages@v4

Private Repositories

In the previous sections we considered the case where all the repositories are public. However in most organizations repository are either private or internal (Github Enterprise), to account for this we need to make sure radius tracker can access this data. To modify the previous example to use private repositories we introduce a few more steps to setup access to private or internal repositories.

jobs:
  run-tracker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout this repository
        uses: actions/checkout@v4

      - name: Generate token
        id: generate-token
        uses: actions/create-github-app-token@v1
        with:
          app-id: ${{ vars.RADIUS_APP_ID }}
          private-key: ${{ secrets.RADIUS_ID_KEY }}
          owner: ${{ github.repository_owner }}

      - name: Add token to configuration
        env:
          GH_TOKEN: ${{ steps.generate-token.outputs.token }}
        run: | 
          sed -i "s/github.com/$GH_TOKEN:$GH_TOKEN@github.com/g" radius-tracker.config.js

The first new step generates an access token. Here we are using a Github App to grant access to the private repository see automating projects using actions.

In the second new step, we rewrite the repository urls using sed to add the token in the previous step. This change should allow the radius tracker to access the private repositories as long as the Github App is installed in the organization and it has been granted access to the target repositories in the radius configuration.

The new workflow file would look like the following:

name: run-tracker

on:
  workflow_dispatch:

jobs:
  run-tracker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout this repository
        uses: actions/checkout@v4

      - name: Generate token
        id: generate-token
        uses: actions/create-github-app-token@v1
        with:
          app-id: ${{ vars.RADIUS_APP_ID }}
          private-key: ${{ secrets.RADIUS_ID_KEY }}
          owner: ${{ github.repository_owner }}

      - name: Add token to configuration
        env:
          GH_TOKEN: ${{ steps.generate-token.outputs.token }}
        run: | 
          sed -i "s/github.com/$GH_TOKEN:$GH_TOKEN@github.com/g" radius-tracker.config.js
          

      - name: Restore cache for tracker
        id: cache-radius-tracker
        uses: actions/cache/restore@v4        
        with: 
          key: cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}
          path: radius-tracker-cache
          restore-keys: |
            cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}

      - name: Run the tracker
        env:
          GH_TOKEN: ${{ steps.generate-token.outputs.token }}
        run: |
          npx radius-tracker timelines ./radius-tracker.config.js

      - name: Save cache for tracker
        uses: actions/cache/save@v4        
        with: 
          key: cache-radius-tracker-${{hashFiles('radius-tracker.config.js')}}-${{github.run_id}}    
          path: radius-tracker-cache
      
      - name: Upload database artifact
        uses: actions/upload-artifact@v4
        with:
          name: tracker-database
          path: usages.sqlite.gz
          
          
  build-static-site:
    runs-on: ubuntu-latest
    needs: run-tracker
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: tracker-database

      - name: Generate static site
        run: |
          npx radius-tracker report --database usages.sqlite.gz
      
      - name: Upload static site artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: radius-tracker-report/

  deploy-to-github-pages:
    runs-on: ubuntu-latest
    needs: build-static-site

    permissions:
      contents: read
      pages: write
      id-token: write
    environment:
      name: github-pages
      url: ${{ steps.deploy-pages.outputs.page_url }}
      
    steps:
      - name: Deploy to GitHub Pages
        id: deploy-pages
        uses: actions/deploy-pages@v4

Last updated