Skip to content

Commit

Permalink
Merge pull request #190 from tkkuehn/deploy
Browse files Browse the repository at this point in the history
Set up non-heroku deploy workflow
  • Loading branch information
tkkuehn authored Feb 8, 2023
2 parents be8e893 + ba19de5 commit a7546bf
Show file tree
Hide file tree
Showing 9 changed files with 1,229 additions and 778 deletions.
13 changes: 6 additions & 7 deletions .github/workflows/afids-validator_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ jobs:
name: Setup environment & test
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
environment: TEST
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10']
Expand All @@ -36,7 +35,7 @@ jobs:
- name: Install poetry
uses: snok/install-poetry@v1
with:
version: 1.2.0
version: 1.3.2
virtualenvs-create: true
virtualenvs-in-project: true

Expand Down Expand Up @@ -64,9 +63,9 @@ jobs:
- name: Setup PostgreSQL db
shell: bash
env:
psql_db_owner: ${{ secrets.PSQL_DB_OWNER }} # PostgreSQL User
psql_db_pw: ${{ secrets.PSQL_DB_PASS }} # PostgreSQL Pass
psql_db_name: ${{ secrets.PSQL_DB_NAME }} # PostgreSQL DB
psql_db_owner: testuser # PostgreSQL User
psql_db_pw: testpass # PostgreSQL Pass
psql_db_name: testdb # PostgreSQL DB
run: |
sudo -u postgres psql --command="CREATE USER $psql_db_owner PASSWORD '$psql_db_pw'"
sudo -u postgres createdb --owner=$psql_db_owner $psql_db_name
Expand All @@ -75,8 +74,8 @@ jobs:
- name: Test AFIDs validator
shell: bash
env:
FLASK_ENV: ${{ secrets.APP_SETTINGS }} # Sets flask environment
DATABASE_URL: postgresql://${{ secrets.PSQL_DB_OWNER }}:${{ secrets.PSQL_DB_PASS }}@localhost/${{ secrets.PSQL_DB_NAME }}
FLASK_ENV: testing # Sets flask environment
DATABASE_URL: postgresql://testuser:testpass@localhost/testdb
run: |
poetry run python -m unittest
Expand Down
7 changes: 0 additions & 7 deletions .github/workflows/afids-validator_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,3 @@ jobs:
publish: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Deploy heroku app
uses: akhileshns/[email protected]
with:
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: afids-validator
heroku_email: ${{ secrets.HEROKU_EMAIL }}
69 changes: 69 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: AFIDs Validator Deploy

on:
workflow_dispatch:
inputs:
comments:
description: "Comments"

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Print author
run: |
echo "Author: ${{ github.event.inputs.author }}"
echo "Date: ${{ github.event.inputs.date }}"
echo "Comments: ${{ github.event.inputs.comments }}"
- uses: actions/checkout@master
with:
ref: refs/heads/master

- name: Install poetry
uses: snok/install-poetry@v1
with:
version: 1.3.2
virtualenvs-create: true
virtualenvs-in-project: true

- name: Install project
run: |
poetry install
- name: Build package with poetry
run: |
poetry build
- name: Write .env file
env:
DATABASE_URL: ${{ secrets.PRODUCTION_DATABASE_URL }}
FLASK_ENV: ${{ secrets.PRODUCTION_FLASK_ENV }}
ORCID_OAUTH_CLIENT_ID: ${{ secrets.PRODUCTION_ORCID_OAUTH_CLIENT_ID }}
ORCID_OAUTH_CLIENT_SECRET: ${{ secrets.PRODUCTION_ORCID_OAUTH_CLIENT_SECRET }}
SECRET_KEY: ${{ secrets.PRODUCTION_SECRET_KEY }}
run: |
echo DATABASE_URL="$DATABASE_URL" >> .env
echo FLASK_ENV="$FLASK_ENV" >> .env
echo ORCID_OAUTH_CLIENT_ID="$ORCID_OAUTH_CLIENT_ID" >> .env
echo ORCID_OAUTH_CLIENT_SECRET="$ORCID_OAUTH_CLIENT_SECRET" >> .env
echo SECRET_KEY="$SECRET_KEY" >> .env
- name: Build release
run: |
DATE=`date +%s`
mkdir -p releases/afidsvalidator-"$DATE"
cp .env releases/afidsvalidator-"$DATE"
WHEEL=`ls dist | grep whl`
cp dist/"$WHEEL" releases/afidsvalidator-"$DATE"
echo WHEEL="$WHEEL" >> $GITHUB_ENV
echo DATE="$DATE" >> $GITHUB_ENV
- name: Deploy release
env:
PRODUCTION_URL: ${{ secrets.PRODUCTION_URL }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
run: |
echo "$PRIVATE_KEY" > .private_key
poetry run python3 fabrictasks.py "$PRODUCTION_URL" releases/afidsvalidator-"$DATE" /opt/afidsvalidator/releases "$WHEEL" /opt/afidsvalidator/venv-afidsvalidator .private_key
11 changes: 11 additions & 0 deletions afidsvalidator.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[uwsgi]
module = afidsvalidator.wsgi:app

master = true
processes = 5

socket = afidsvalidator.sock
chmod-socket = 660
vacuum = true

die-on-term = true
7 changes: 6 additions & 1 deletion afidsvalidator/config.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Configuration classes for flask/heroku."""

import os
from dataclasses import dataclass

from dotenv import load_dotenv

load_dotenv()


class Config(object):
@dataclass
class Config:
"""Configuration class
This class contains all of the global configuration variables needed for
Expand All @@ -31,6 +33,7 @@ class Config(object):
ORCID_OAUTH_CLIENT_SECRET = os.environ.get("ORCID_OAUTH_CLIENT_SECRET")


@dataclass
class ProductionConfig(Config):
"""Config used in production"""

Expand All @@ -39,13 +42,15 @@ class ProductionConfig(Config):
TESTING = False


@dataclass
class DevelopmentConfig(Config):
"""Config used in development"""

DEVELOPMENT = True
DEBUG = True


@dataclass
class TestingConfig(Config):
"""Config used for pytest"""

Expand Down
2 changes: 2 additions & 0 deletions afidsvalidator/wsgi.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Entrypoint for flask"""

from afidsvalidator import create_app

app = create_app()
87 changes: 87 additions & 0 deletions fabrictasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import argparse
from pathlib import Path, PurePath

from fabric import Connection, config


def push_release(
connection: Connection,
new_release_path: Path,
remote_releases_dir: PurePath,
wheel_name: str,
):
remote_release_new = str(remote_releases_dir / new_release_path.name)
connection.run(f"mkdir -p {remote_release_new}")
wheel_path = str(new_release_path / wheel_name)
connection.put(wheel_path, remote_release_new)
connection.put(str(new_release_path / ".env"), remote_release_new)
link_name = str(remote_releases_dir.parent / "current")
connection.run(f"ln -s {remote_release_new} {link_name}")


def install_wheel(connection: Connection, venv_path: str, wheel_path: str):
connection.run(
f"source {venv_path}/bin/activate && pip install {wheel_path}"
)


def upgrade_db(
connection: Connection, new_release_remote: str, venv_path: str
):
connection.run(
f"set -a && . {new_release_remote}/.env && set +a && "
f"{venv_path}/bin/flask -A afidsvalidator.wsgi:app db upgrade "
f"-d {venv_path}/lib/python3.8/site-packages/migrations"
)


def restart_validator(connection: Connection):
connection.sudo("systemctl restart afidsvalidator.service")


def deploy(
connection: Connection,
new_release_path: Path,
remote_releases_dir: PurePath,
wheel_name: str,
venv_path: PurePath,
):
push_release(connection, new_release_path, remote_releases_dir, wheel_name)
wheel_path = str(remote_releases_dir / new_release_path.name / wheel_name)
install_wheel(connection, str(venv_path), wheel_path)
upgrade_db(
connection,
str(remote_releases_dir / new_release_path.name),
str(venv_path),
)
restart_validator(connection)


def build_parser():
parser = argparse.ArgumentParser()
parser.add_argument("host")
parser.add_argument("new_release_path", type=Path)
parser.add_argument("remote_releases_dir", type=PurePath)
parser.add_argument("wheel_name", type=str)
parser.add_argument("venv_path", type=PurePath)
parser.add_argument("identity_path", type=Path)
return parser


def main():
parser = build_parser()
args = parser.parse_args()
deploy(
Connection(
args.host, connect_kwargs={"key_filename": str(args.identity_path)}
),
args.new_release_path,
args.remote_releases_dir,
args.wheel_name,
args.venv_path,
)


if __name__ == "__main__":
config.Config()
main()
Loading

0 comments on commit a7546bf

Please sign in to comment.