GitHub Integration with Python

Problem

A Publisher wants to create an all-in-one status dashboard for their project hosted on Posit Connect, allowing users to see tasks assigned to them in GitHub right from the Connect dashboard. The Publisher wants to limit the display to issues assigned to the logged-in user.

Solution

The Flask and Streamlit examples below use the GitHub OAuth Integration feature of Posit Connect to show custom GitHub resources based on the logged-in user.

requirements.txt
Flask==3.0.3
posit-sdk==0.5.0
PyGithub==2.4.0
app.py
# -*- coding: utf-8 -*-
# mypy: ignore-errors
import os

from posit import connect
from github import Github
from github import Auth
from flask import Flask, request

app = Flask(__name__)


@app.route("/")
def usage():
    return "<p>Try: <pre>GET /my_issues<pre></p>"


@app.route("/my_issues")
def my_issues():
    """
    Flask example API that returns issues assigned to
    the logged-in GitHub user via the GitHub OAuth2
    Integration.
    """
    issues = []

    # initialize the Connect python sdk client if running on Connect
    if os.getenv("RSTUDIO_PRODUCT") == "CONNECT":
        client = connect.Client()

        # grab the user session token from headers
        user_session_token = request.headers.get("Posit-Connect-User-Session-Token")

        try:
            # fetch the access token using the session token
            access_token = client.oauth.get_credentials(user_session_token).get(
                "access_token"
            )
        except connect.errors.ClientError as e:
            if e.error_code == 219:
                return "Your GitHub refresh token has expired. Please log out and log in to the integration."
    else:
        access_token = os.getenv("GITHUB_TOKEN")

    # using an access token
    auth = Auth.Token(access_token)

    # Public Web Github
    g = Github(auth=auth)

    # Get issues assigned to the authenticated user:
    for issue in g.get_user().get_user_issues():
        issues.append(issue.number)

    # Close connection
    g.close()

    return issues

Running the app locally

Terminal
export CONNECT_SERVER=<connect-server>
export CONNECT_API_KEY=<connect-api-key>
GITHUB_TOKEN=<github-token> flask --app app run
requirements.txt
pandas
streamlit
posit-sdk==0.5.0
PyGithub==2.4.0
app.py
# -*- coding: utf-8 -*-
# mypy: ignore-errors

import os
import streamlit as st
from posit import connect
from github import Github
from github import Auth
import pandas as pd

issues = []

# initialize the Connect python sdk client if running on Connect
if os.getenv("RSTUDIO_PRODUCT") == "CONNECT":
    client = connect.Client()

    # grab the user session token from headers
    user_session_token = st.context.headers.get("Posit-Connect-User-Session-Token")

    try:
        # fetch the access token using the session token
        access_token = client.oauth.get_credentials(user_session_token).get(
            "access_token"
        )
    except connect.errors.ClientError as e:
        if e.error_code == 219:
            st.write(
                "Your GitHub refresh token has expired. Please log out and log in to the integration."
            )
else:
    access_token = os.getenv("GITHUB_TOKEN")

# using an access token
auth = Auth.Token(access_token)

# Public Web Github
g = Github(auth=auth)

issue_title = []
issue_url = []
# Get issues assigned to the authenticated user
for issue in g.get_user().get_user_issues():
    issue_url.append(issue.html_url)
    issue_title.append(issue.title)

github_user = g.get_user()

# Close connection
g.close()

df = pd.DataFrame({"title": issue_title, "url": issue_url})

st.write(
    f"Hello, {github_user.name}! You have the following open GitHub issues assigned to you:"
)
st.write(df)

Running the app locally

Terminal
export CONNECT_SERVER=<connect-server>
export CONNECT_API_KEY=<connect-api-key>
GITHUB_TOKEN=<github-token> streamlit run app.py