Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wy/wakeup actions lambda #6

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
lambda_package/
lambda_package.zip

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
# KeepActionsAlive
Prevent scheduled GitHub Actions from becoming disabled after 60 days

## How to use

This requires installing the github api package, which can be done with `python -m pip install github`

Afterwards this can be started by setting the following environment variables:
* `GH_LOGIN_OR_TOKEN`
* Used both for API calls to get repo/organization info, and to send the request to re-enable workflows
* A Github [Personal Access Token (PAT)](https://docs.github.com/en/rest/overview/other-authentication-methods#via-oauth-and-personal-access-tokens)
* `GH_ORGANIZATION`
* The name of the organization you would like to work with
* Used to fetch the list of all owned repositories, and then all workflows
22 changes: 22 additions & 0 deletions build_lambda_package.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh
# For best results run this in a manylinux docker container or AL2 container
# Some packages ignore the `plat-name` build option

# target build platform options: https://github.com/pypa/manylinux
PLATFORM=manylinux1_x86_64
TARGET_DIR=./lambda_package/lambda_wheel/

. ./venv/bin/activate
pip install -e ".[deploy]"
python -m pip wheel \
--wheel-dir="$TARGET_DIR" \
--build-option "--plat-name=$PLATFORM" \
--no-binary ":all:" \
-e .

cp ./lambda_package_files/* ./lambda_package/.
mkdir ./lambda_package/src
cp src/keep_actions_alive.py ./lambda_package/src/.
cp src/lambda.py ./lambda_package/src/.
cp ./setup.cfg ./lambda_package/.
cp ./setup.py ./lambda_package/.
1 change: 1 addition & 0 deletions lambda_package_files/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-e .
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-e .
Empty file added setup.cfg
Empty file.
26 changes: 26 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from setuptools import find_packages, setup # type: ignore

REQUIREMENTS = [
"pygithub",
]

DEPLOY_DEPS = [
# Used to zip up the code
"wheel",
]

EXTRAS = {
"deploy": DEPLOY_DEPS
}

setup(
name="KeepActionsAlive",
version="0.0.1",
description="Re-enables Github Workflows disabled due to inactivity",
author="Invenia Technical Computing",
url="https://github.com/invenia/KeepActionsAlive",
packages=find_packages(),
install_requires=REQUIREMENTS,
include_package_data=True,
extras_require=EXTRAS,
)
56 changes: 56 additions & 0 deletions src/keep_actions_alive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python

from github import Github
import os
import pprint
import requests

IS_LAMBDA = bool(os.getenv("AWS_EXECUTION_ENV"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
IS_LAMBDA = bool(os.getenv("AWS_EXECUTION_ENV"))



def get_parameters():
# Add more options for adding arguments here,
# such as CLI args, AWS Secrets Manager, config file, etc.

# Get keyword arguments from environment variables
return {
"login_or_token": os.getenv("GH_LOGIN_OR_TOKEN"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be an environment variable. It needs to be stored in SecretsManager and using boto to retrieve it.

"organization": os.getenv("GH_ORGANIZATION"),
}


def keep_actions_alive(parameters):
pp = pprint.PrettyPrinter(indent=4)

login_or_token = parameters["login_or_token"]
organization = parameters["organization"]

g = Github(login_or_token=login_or_token)

# Get all repos that are not forks and are not archived
# Only supports repos owned by an organization for now,
# but could be changed to users
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# but could be changed to users
# but could be changed to users
# TODO: Support non-organizational repositories

repos = g.get_organization(organization).get_repos()
owned_repos = [r for r in repos if not r.fork and not r.archived]

for repo in owned_repos:
# Get all workflows disabled from inactivity
disabled_workflows = [
w for w in repo.get_workflows() if w.state == "disabled_inactivity"
]

if login_or_token: # Use token authentication
for workflow in disabled_workflows:
# There's no documented pygithub API call for enabling the
# workflow, so the rest API should work here
enable_url = f"{workflow.url}/enable"
token_header = {"Authorization": f"Bearer {login_or_token}"}
requests.put(enable_url, headers=token_header)
else:
# No authentication, so just output the disabled workflows
pp.pprint(disabled_workflows)


if __name__ == "__main__":
parameters = get_parameters()
keep_actions_alive(parameters)
30 changes: 30 additions & 0 deletions src/lambda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env python
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the point of this file, why not just have everything in one script?


import boto3
import json
import os

import keep_actions_alive


# Specifically gets parameters for running in a Lambda
def get_parameters():
sm_client = boto3.client("secretsmanager")
secret_key = os.getenv("GH_LOGIN_OR_TOKEN_KEY")
login_or_token = json.loads(
sm_client.get_secret_value(SecretId=secret_key)["SecretString"]
)["Personal Access Token"]
return {
"login_or_token": login_or_token,
"organization": os.getenv("GH_ORGANIZATION"),
}


# Lambda entry point. Does not use `event` and `context`
def lambda_handler(*kwargs):
keep_actions_alive.keep_actions_alive(get_parameters())


# mainly for testing
if __name__ == "__main__":
lambda_handler()