Воссоздание графика вклада GitHub с помощью Flask и Google Sheets


Я помешана на продуктивности. Раньше я следила за выполнением своих задач каждый день с помощью ручки и бумаги. Затем, когда задачи стали более сложными, я начала записывать их в электронную таблицу. Так продолжалось в течение месяца, но потом я потеряла мотивацию. Мне нужен был толчок, чтобы следовать своему распорядку. Вот тут-то и появляется график вклада.

Если вы пользуетесь GitHub, то видели в своем профиле тепловую карту, которая показывает ваши вклады (коммиты, пулл-реквесты и т.д.) за каждый день в году, как продемонстрировано на рисунке выше. Я работала над проектом каждый день, чтобы поддерживать непрерывную полосу в GitHub, и все время ненавидела этот серый квадрат в своем профиле! Мне попадался туториал по созданию графика вклада с помощью Node.JS, но я предпочитаю Python, и поэтому сделала то же самое, используя Flask и Google Sheets API.

В этом руководстве я пройду пошагово через все этапы, начиная от создания приложения и заканчивая его развертыванием на Heroku. Я также поделюсь найденными мной ошибками и их решениями.

Настройка среды для проекта

Давайте начнем с создания среды для работы над проектом. Я предполагаю, что вы уже установили Python (желательно Python 3) и pip в свою систему. В противном случае загрузите Python отсюда и следуйте инструкциям. Pip — это менеджер пакетов для Python, который помогает устанавливать дополнительные библиотеки и зависимости, необходимые для вашего приложения. Проверьте, установлен ли pip с помощью этой команды в командной строке: pip — version.

  • Вам понадобится изолированная среда для вашего приложения и его зависимостей, поэтому начните с настройки виртуальной среды. Перейдите в новый каталог, где вы хотите разместить свой проект, откройте командную строку и установите virtualenv с помощью команды pip install virtualenv.
  • Установите virtualenvwrapper, который представляет собой набор расширений для virtualenv, набрав pip install virtualenvwrapper-win. (Примечание: эта команда предназначена только для Windows).
  • Создайте виртуальную среду, введя команду mkvirtualenv your-env-name.
  • Вы можете активировать виртуальную среду с помощью команды workon your-new-name и деактивировать ее с помощью deactivate.
  • После запуска виртуальной среды установите Flask, введя команду pip install flask.
  • Создание электронной таблицы вклада

    Давайте теперь перейдем к созданию электронной таблицы, которая будет выступать в качестве базы данных. На мою таблицу можно взглянуть здесь (необходимо запросить доступ).

    В этой таблице есть четыре поля:

    • Date (Дата). У меня это поле отформатировано так же, как и в GitHub, и вы можете отформатировать его так, как захочется вам.
    • Task (Задача). В этом поле содержится название каждой задачи и ее описание (необязательно).
    • Number of Tasks (Число задач). Здесь содержится количество задач.
    • Level (Уровень). Здесь используется формула =IF(C2=0,”0", if(C2<=2,”1", if(C2<=4,”2",”3"))) для расчета уровня на основе количества задач. Вся колонка заполняется, исходя из этой формулы.

    Вы можете настроить поля по своему усмотрению, но у вас должно быть хотя бы одно поле, схожее с полем “Уровень”, потому что оно используется для определения цвета, которым заполняется каждый квадрат в графике.

    Получение API, чтобы иметь возможность использовать таблицу

    Этот шаг критически важен, поскольку он позволяет нашему приложению подключаться к Google Sheets:

    • Перейдите в консоль разработчика Google и авторизуйтесь через свой Google-аккаунт.
    • Создайте новый проект и кликните на кнопку, включающую API:
    Кнопка подключения API
    • Найдите Google Drive API и нажмите кнопку “ENABLE”:
    • После того, как API будет подключен, нажмите кнопку “Создать учетные данные” (“Create Credentials”). Откроется мастер учетных данных. Заполните каждое поле, как показано ниже:
    Мастер учетных данных
    • На втором шаге дайте имя аккаунту своего сервиса и перейдите по “Выбрать роль > Проект > Редактор” (Select Role > Project > Editor). Нажмите кнопку “Продолжить”, и для вас будет сгенерирован .JSON-файл, который выглядит так же, как приведенный ниже пример. Переименуйте его в Client_Secret.json.
    Client_Secret.json
    • Если вы попытаетесь получить доступ к своей электронной таблице сразу же вслед за этим, то получите ошибку Insufficient Permission.
    • Вдобавок к Google Drive API вам также необходимо подключить Google Sheets API.
    • Как только вы подключите этот API, перейдите к таблице, из которой хотите извлечь данные, и нажмите кнопку “Поделиться” (“Share”).
    Поделитесь своей таблицей
    • В файле Client_Secret.json будет client_email. Скопируйте этот e-mail, вставьте его в всплывающее окно и нажмите “Отправить”.

    Вот и всё! Теперь давайте извлечем данные из электронной таблицы и отобразим их в нашем приложении.

    Структурирование приложения Flask

    Contribution Graph |--Static |--CSS |--design.css client_secret.json |--templates |--index.html |--app.py |--spreadsheet.py |--Procfile |--requirements.txt

    Не волнуйтесь! Я объясню, для чего нужен каждый файл и какую задачу он выполняет, по ходу дела. Этот пример нужен для того, чтобы дать вам примерное представление о том, как здесь структурированы папки. 

    Получение доступа к данным Google Sheets

    Теперь давайте посмотрим, можем ли мы получить доступ к данным из нашей таблицы. Существует популярный Python API под названием gspread, который позволяет легко читать (и записывать) из Google Sheets и Oauth, а также дает вашему приложению вызывать Google API от имени учетной записи сервиса. Установите gspread и oauth2 с помощью pip —  pip install gspread oauth2.

    Файл JSON расположен в папке Static (здесь хранятся все статические файлы, которые не изменяются, такие как CSS и JS), поэтому получите к нему доступ из корня с помощью модуля os —  os.path.realpath(os.path.dirname(__file__)). Затем создайте переменную scope, содержащую ссылку на фид на диске, и переменную creds для доступа к файлу JSON с использованием учетных данных сервиса. 

    Теперь вы можете получить доступ к таблице, используя client.open(‘Daily Contribution’).sheet1, где Daily Contribution — это имя файла, а sheet1 — имя первой таблицы. Мы будем хранить значения каждого столбца в переменной и создадим общую переменную data, которая содержит их все, присваивая возвращаемому значению функции getData(), как показано в коде ниже:

    import os import gspread from oauth2client.service_account import ServiceAccountCredentials SITE_ROOT = os.path.realpath(os.path.dirname(__file__)) json_file = os.path.join(SITE_ROOT,'static', 'Client_Secret.json') scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive'] creds = ServiceAccountCredentials.from_json_keyfile_name(json_file, scope) client = gspread.authorize(creds) sheet = client.open('Daily Contribution').sheet1 def getData(): date = sheet.col_values(1, value_render_option='FORMATTED_VALUE') task = sheet.col_values(2, value_render_option='FORMATTED_VALUE') numberOfTasks = sheet.col_values(3, value_render_option='FORMATTED_VALUE') level = sheet.col_values(4, value_render_option='FORMATTED_VALUE') data = [date, task, level] return data

    Чтобы убедиться, что все работает как надо, вы можете вывести data в командной строке, воспользовавшись python spreadsheet.py.

    Данные для нашего приложения уже готовы. А теперь давайте сделаем его красивым!

    Внешний вид приложения

    Создайте файл index.html и поместите его в папку “templates”. Flask в общем случае ищет HTML-файлы внутри этой папки, поскольку он использует библиотеку шаблонов Jinja для отрисовки шаблонов.

    <!DOCTYPE html> <html> <head> <title>Contribution Graph</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/design.css') }}" /> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <link href="https://fonts.googleapis.com/css2?family=Lemonada:[email protected];400&display=swap" rel="stylesheet"> </head> <body> <h1>My Daily Contribution Graph</h1> <div class="graph"> <ul class="months"> <li>Jan</li> <li>Feb</li> <li>Mar</li> <li>Apr</li> <li>May</li> <li>Jun</li> <li>Jul</li> <li>Aug</li> <li>Sep</li> <li>Oct</li> <li>Nov</li> <li>Dec</li> </ul> <ul class="days"> <li>Sun</li> <li>Mon</li> <li>Tue</li> <li>Wed</li> <li>Thu</li> <li>Fri</li> <li>Sat</li> </ul> <ul class="squares"> {% for i in range(1,366) %} {% if data[1][i] %} <li data-toggle="tooltip" data-placement="bottom" data-animation="false" delay="0" title="{{data[1][i]}} on {{data[0][i]}}" data-level="{{data[2][i]}}"></li> {% else %} <li data-toggle="tooltip" data-placement="bottom" data-animation="false" delay="0" title="No Contribution on {{data[0][i]}}" data-level="{{data[2][i]}}"></li> {% endif %} {% endfor %} </ul> </div> <div class="contributeLegend"> <p class="legendTitle">Legend</p> <ul class="legendSquares"> <li data-toggle="tooltip" data-placement="bottom" data-animation="false" delay="0" title="No Contribution"></li> <li data-toggle="tooltip" data-placement="bottom" data-animation="false" delay="0" title="Less than 2 Contributions" data-level="1"></li> <li data-toggle="tooltip" data-placement="bottom" data-animation="false" delay="0" title="Less than 4 Contributions" data-level="2"></li> <li data-toggle="tooltip" data-placement="bottom" data-animation="false" delay="0" title="More than 4 Contributions" data-level="3"></li> </ul> </div> <script> var squares = document.querySelector(".squares") </script> </body> </html>

    Что касается CSS, то я находила туториал, который сэкономил мне время, однако вы можете реализовать его так, как захочется именно вам.

    Я также создала систему условных обозначений, включая всплывающие подсказки, и изменила цвет квадратов на розовый. Вы также можете изменять внешний вид приложения по своим предпочтениям!

    Соединение данных с шаблоном

    Создайте промежуточный файл, который отправляет данные в HTML-файлы, под названием app.py. Импортируйте spreadsheet.py и присвойте переменной значение, возвращаемое функцией getData(). Передайте переменную в функцию render_template() вместе с HTML-кодом.

    from flask import Flask, render_template, json import spreadsheet app = Flask(__name__) @app.route("/") def main(): data = spreadsheet.getData() return render_template('index.html', data=data) if __name__ == "__main__": app.jinja_env.auto_reload = True app.config['TEMPLATES_AUTO_RELOAD'] = True app.run(host="0.0.0.0", port=5000, threaded=True)

    Код в блоке if автоматически перезагружает содержимое приложения всякий раз, когда в него вносятся изменения.

    Теперь запустите приложение из командной строки, используя команду python app.py (убедитесь, что вы активировали виртуальную среду). Если все пройдет хорошо, ваше приложение запустится и будет работать в localhost http://127.0.0.1:5000/!

    Развертывание приложения с использованием Heroku

    Использование Heroku требует, чтобы у вас был установлен Git.

  • Загрузите Heroku CLI отсюда и следуйте инструкциям по установке.
  • Откройте командную строку (рекомендуется использовать Git Bash) и проверьте, установлен ли Heroku, применив команду Heroku --version.
  • Создайте бесплатную учетную запись на сайте Heroku здесь.
  • Настроив аккаунт, войдите в него с помощью оболочки, набрав Heroku login -i и введя свои учетные данные.
  • Мы будем использовать gunicorn для развертывания нашего приложения, поскольку он относительно быстрый и может обрабатывать несколько запросов одновременно. Установите его с помощью команды pip install gunicorn.
  • Создайте файл requirements.txt, который информирует Heroku о зависимостях для нашего приложения, набрав pip freeze > requirements.txt.
  • Из-за своей глупости мне пришлось столкнуться со многими ошибками. Я заморозила файл требований, не активировав виртуальную среду. Всегда удостоверяйтесь, что вы работаете при включенной виртуальной среде.
  • Создайте новый файл в корневом каталоге и введите туда web: gunicorn --bind 0.0.0.0:$PORT app:app. Назовите его Procfile. (Примечание: не используйте никаких расширений). Procfile сообщает Heroku, какие команды будут выполняться приложением при запуске.
  • В app:app первое app отсылается к имени файла (к примеру, app.py), а второе app отсылается к app = Flask(__name__)
  • У меня была ошибка H14 error: no web processes running, но мне удалось избавиться от нее с помощью следующей команды: heroku ps:scale web=1. Она информирует Heroku, что мы не запускаем никаких веб-Dyno. Если вы не поняли, о чем речь, отлично — продолжайте дальше.
  • Теперь инициируйте пустой репозиторий git внутри вашего рабочего каталога с помощью git init.
  • Теперь добавьте все файлы через git add . и сделайте коммит git commit -m "Initial Commit".
  • Создайте новое приложение на Heroku с использованием heroku create, что генерирует ссылку для вашего приложения и URL-адрес удаленного репозитория, а затем введите команду heroku open, которая откроет приложение в вашем браузере.
  • Добавьте удаленный репозиторий через git remote add heroku 'repo-link-generated-on-heroku-create'.
  • Теперь отправьте туда изменения с помощью git push heroku master.
  • Ваше приложение теперь работает в интернете!

    Здесь можно посмотреть мой вариант.

    Также вы можете просмотреть мои итоговые файлы на GitHub.


    Перевод статьи Padhma Sahithya: Recreate GitHub’s Contribution Graph Using Flask and Google Sheets


    Поделиться статьей:


    Вернуться к статьям

    Комментарии

      Ничего не найдено.