Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ notifications:

sudo: false

env:
global:
- GITHUB_USER=username
- GITHUB_PASS=password

language: python

cache: pip
Expand Down
24 changes: 23 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,29 @@ Currently ``github-file`` implements one subcommand:

This will update the configuration of your repository on GitHub so that it
matches what is described in a file called (by default) ``Githubfile`` in the
``.github`` folder.
``.github`` folder. Here's an example of such a file:

.. code-block:: ini

[core]
owner = jacquerie
repo = github-file
description = Configure your GitHub repository from a file,
without having to click around in the UI.

[features]
has_issues = true
has_wiki = false

The meaning of these options is explained in GitHub's API documentation at
https://developer.github.com/v3/repos/#edit, although not all options are
currently available. Here's what's currently configurable:

- ``description``
- ``homepage``
- ``private``
- ``has_issues``
- ``has_wiki``


Author
Expand Down
42 changes: 41 additions & 1 deletion github_file/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,57 @@
import os

import click
from dotenv import find_dotenv, load_dotenv
from github3 import GitHub
from six.moves import configparser

DEFAULT_FILENAME = os.path.join('.github', 'Githubfile')


@click.group()
@click.version_option()
def cli():
pass
load_dotenv(find_dotenv())


@cli.command()
@click.option('-f', '--file', 'filename', default=DEFAULT_FILENAME)
def update(filename):
"""Update the repo to match the config file."""
parser = configparser.ConfigParser()
parser.read(filename)

owner = parser.get('core', 'owner')
repo = parser.get('core', 'repo')

description = ''
if parser.has_option('core', 'description'):
description = ' '.join(parser.get('core', 'description').split())
homepage = ''
if parser.has_option('core', 'homepage'):
homepage = parser.get('core', 'homepage')
private = False
if parser.has_option('core', 'private'):
private = parser.getboolean('core', 'private')

has_issues = False
if parser.has_option('features', 'has_issues'):
has_issues = parser.getboolean('features', 'has_issues')
has_wiki = False
if parser.has_option('features', 'has_wiki'):
has_wiki = parser.getboolean('features', 'has_wiki')

config = {
'description': description,
'homepage': homepage,
'private': private,
'has_issues': has_issues,
'has_wiki': has_wiki,
}

github_user = os.getenv('GITHUB_USER')
github_pass = os.getenv('GITHUB_PASS')
github = GitHub(github_user, github_pass)

repository = github.repository(owner, repo)
repository.edit(repo, **config)
4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@

install_requires = [
'click~=6.0,>=6.7',
'github3.py~=1.0,>=1.1.0',
'python-dotenv~=0.0,>=0.8.2',
'six~=1.0,>=1.11.0',
]

docs_require = []

tests_require = [
'flake8-future-import~=0.0,>=0.4.4',
'pytest-cov~=2.0,>=2.5.1',
'pytest-vcr~=0.0,>=0.3.0',
'pytest~=3.0,>=3.2.3',
]

Expand Down
136 changes: 136 additions & 0 deletions tests/cassettes/test_update_uses_the_provided_filename.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
interactions:
- request:
body: null
headers:
Accept: [application/vnd.github.v3.full+json]
Accept-Charset: [utf-8]
Accept-Encoding: ['gzip, deflate']
Authorization: [Basic dXNlcm5hbWU6cGFzc3dvcmQ=]
Connection: [keep-alive]
Content-Type: [application/json]
User-Agent: [github3.py/1.1.0]
method: GET
uri: https://api.github.com/repos/jacquerie/github-file
response:
body:
string: !!binary |
H4sIAAAAAAAAA6WYUW/iOBDHv0rE61FCunSvRar2VrfVXk/X7t6JvVv1BZnEELeJnbUdWIj63e9v
O5AEVdDiFwTG8/N4PDOecdVjSW8cjYYXV9HoIur3uEjo1Iz17j7drL5kf2bx56sN+f7PMuZPP+8/
fYy+TG6G95Ob6x4mk5xi5oLptJydzVlGMTgvs2xa//NI4h8llYyG3TlixansjateJhaMA7GbCIBZ
/d1ldH457Krz9/t/v99n8ePd6G5yO7r7eG1UIEuiiZyWMgMl1bpQ4zB0g+p84FYtFZWx4JpyPYhF
Hpahw39YXo+AWMgaYreNgT1YwWqOEwZMhW19U51newq4de389sy5yDKxgvy+vgeXCHdixroWwfji
FATEqlDolMJg2Maz2TxT+o3qWJEKJ6o0PMVAFI5A0uRtKtVCUMg4w3MVSloISytnKpas0EzwN6rW
EQVKyAXhbENOQEFUgWCUeqMSVgSidAmHe6Osk6nCQrIlidfGHJLGlC1h3VN4e8LA6XVhYvYbzt/Y
mmk6JUlugnBOMkWf+z27tsYkO9BHVL3Kv/dCPKG7Q8Ryvws+Z4tS0mAtShl8ZvqPchZYSzEt5DqY
S5EHJDA5pB+skFBEqYOULOGygRZBnLH4KSBSlDwJGA/gw8G32wF2MBfyaafqwci1qzXxuKev4Rw5
rAMAxCjEoc4TXXtQjHQV4rMOrBjRTmZCEtjIA9vBVGH7p/EwTUnuQbfiwKRC+FjQigPDlCrpq5z9
0HlYigq38cTLfOYS3mui6BDYyUNPohRbcEo9LLdDVOE2H88k4XHqA90SqtB9sydMFh5qGmlAZpmY
eVBwJ4YWUYUqJe7u0VM/zQzTEDpISeeeahrCDqml1xlbFQ1iB8TFp3HcHjpuCWFVWzIjfFGShQ9z
h8BJm6t5QTZHC5VDcdIwADTVl2Sz0jeNNRSjpasTENc+pmwgDdKWHoermYNbbxUwdvN5zo4VAod4
NaDj5N5Q45f7YPP7eM1yTFVDqMIm47qEXrNPt2qd0bc6tleoi3sPN9gSwuqXgujUZCcsVBBJT1e4
BoTVjKCuGgwGVUqJrZdzKr1i1ckDRGScojY8XcdqS0D9khNtq/C5UTFBVZ4JknjYdIcAzh3e6Xo6
+faZF2gzPZSz4m1ejspTacF9cmjDaJO50GzO4tc0IYdCq4OpPijGY9onWdaHl2oWM/gtimVzdigZ
qY9tnDy2gPbedSAZhQt7WFtSR6hC1zAmtMjE2jPXtCAmXCVF05JMiUa7cT6MLs+Gv55F0SS6GA+j
8Wj4gDllkbww52JyHo3P342HV2ZOUar0BQz+301B6qw9Gd/w3IBPvH90u/12d2GeD0BWKm3EfmuE
xi++ktRCcQaX3Iub16633L/DjglCyVTktEAl4V5CFNvg20WnIojRg8HGeJxZEY1SFbdvM7StIiD+
dY0mjhskUVMXv72xlqXpKDFSSPFIY63aY03GaE1csSfW9KJG0hQ6uxHXtzUa5ExKUT8IcQT5Lkni
caduaEVBea1RW3UWU66w3co0cdgALm1oX79k3d1Ogr/qGTBHkfysX8luJ8axus9P3ecctK4GrMIa
2Hphi99PPmePD/9dbB4mN5semm/XRxrrtrTsWNv+SOiclJmeuhLfKEuUth19QWUOa5u3E7OVurd3
dje+vbW3SYDuO1ZFGhGrqfpREviovV2209w/dgi2MoVM9x9Jze3WleFUr9AOt2zbLtXqo4qe/wc+
aoEGfBQAAA==
headers:
access-control-allow-origin: ['*']
access-control-expose-headers: ['ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit,
X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
X-Poll-Interval']
cache-control: ['private, max-age=60, s-maxage=60']
content-encoding: [gzip]
content-security-policy: [default-src 'none']
content-type: [application/json; charset=utf-8]
date: ['Sun, 15 Jul 2018 22:25:30 GMT']
etag: [W/"497305d747d01b0c563b8f38a552cf10"]
last-modified: ['Sun, 15 Jul 2018 21:23:09 GMT']
referrer-policy: ['origin-when-cross-origin, strict-origin-when-cross-origin']
server: [GitHub.com]
status: [200 OK]
strict-transport-security: [max-age=31536000; includeSubdomains; preload]
vary: ['Accept, Authorization, Cookie, X-GitHub-OTP']
x-content-type-options: [nosniff]
x-frame-options: [deny]
x-github-media-type: [github.v3; param=full; format=json]
x-github-request-id: ['8982:7DB6:A098CBC:147496BE:5B4BC9D9']
x-ratelimit-limit: ['5000']
x-ratelimit-remaining: ['4999']
x-ratelimit-reset: ['1531697130']
x-runtime-rack: ['0.082371']
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
- request:
body: !!python/unicode '{"has_wiki": false, "name": "github-file", "has_issues":
true, "homepage": "", "private": false, "description": "Configure your GitHub
repository from a file, without having to click around in the UI."}'
headers:
Accept: [application/vnd.github.v3.full+json]
Accept-Charset: [utf-8]
Accept-Encoding: ['gzip, deflate']
Authorization: [Basic dXNlcm5hbWU6cGFzc3dvcmQ=]
Connection: [keep-alive]
Content-Length: ['202']
Content-Type: [application/json]
User-Agent: [github3.py/1.1.0]
method: PATCH
uri: https://api.github.com/repos/jacquerie/github-file
response:
body:
string: !!binary |
H4sIAAAAAAAAA6WYYW/iOBCG/0rE16MNUNhrkaq91W3V6+na3Tuxd6t+QSYxxG1iZ20HFqL+93tt
B5KgClosVRUYz+PxeGY847LD4s64P+yNrvrDUb/b4SKmUzPWuf98s/qS/plGt1cb8v2fZcSffz58
/tT/MrnpPUxurjuYTDKKmQumk2J2NmcpxeC8SNNp9csTiX4UVDIatueIFaeyMy47qVgwDsRuIgBm
9YvL/uCy11bn7w//fn9Io6f74f3kbnj/6dqoQJZEEzktZApKonWuxmHoBtXg3K1aKCojwTXl+jwS
WViEDv9xeT0EYiEriN02BvZgOas4ThgwFTb1TXSW7ing1rXzmzPnIk3FCvL7+h5cItyJGetaBOOL
UxAQK0OhEwqDYRsvZvNM6XeqY0VKnKjS8BQDUTgCSeP3qVQJQSHjDC9lKGkuLK2YqUiyXDPB36la
SxQoIReEsw05AQVRBYJR6p1KWBGI0iUc7p2yTqYMc8mWJFobc0gaUbaEdU/h7QkDp9e5idlvOH9j
a6bplMSZCcI5SRV96Xbs2hqT7EAXUfUm/94L8ZjuDhHL/S74nC0KSYO1KGRwy/QfxSywlmJayHUw
lyILSGBySDdYIaGIQgcJWcJlAy2CKGXRc0CkKHgcMB7Ah4Nvd+fYwVzI552qByPXrlbH456+hnPk
sA4AEKMQhzrPdO1BMdJliP9VYEWIdjITksBGHtgWpgybX42HaUoyD7oVByYRwseCVhwYplRB3+Ts
h87DUlS4jSdeZDOX8N4SRYfATh56EqXYglPqYbkdogy3+XgmCY8SH+iWUIbukz1hsvBQ00gDMkvF
zIOCOzG0iDJUCXF3j576aWaYhtBCSjr3VNMQdkgtvc7YqmgQOyAuPo3j9tBxSwjLypIp4YuCLHyY
OwRO2lzNC7I5WqgcipOaAaCpviSbFb5prKYYLV2dgLj2MWUNqZG29DhczRzceqOAsZvPMnasEDjE
qwAtJ/eGGr/cB5vvx2uWY6oaQhnWGdcl9Ip9ulWrjL7VsblCVdx7uMGWEJa/5EQnJjthoZxIerrC
FSAsZwR11fn5eZlQYuvljEqvWHXyABEZJagNT9ex3BJQv2RE2yp8blSMUZWngsQeNt0hgHOHd7qe
Tr555jnaTA/lrHiTl6HyVFpwnxxaM5pkLjSbs+gtTcih0Gphyo+K8Yh2SZp24aWaRQx+i2LZnB1K
RupjGyePLaC9dx1ISuHCHtaW1BHK0DWMMc1TsfbMNQ2ICVdJ0bTEU6LRbgx6/cuz3q9n/f6kPxr3
+uNh7xFzijx+Zc5oMhiMB6PxhZ2TFyp5BTO4GOOvd2WmIHVWnoxPeG7Af7x/tLv9Zndhng8gplRS
i/1WC41ffSWphKIULrkXN29db7l/hx0ThJKJyGiOSsK9hCi2wadRqyKI0IPBxnicWRGNUhW3bz20
rSIg/nWNJo4bJFFTF7+dsZaF6SgxkkvxRCOtmmN1xmhMXLFnVveiRtIUOrsR17fVGmRMSlE9CHEE
+S5J4nGnamhFTnmlUVN1FlGusN3SNHHYAC5taF+9ZN3fTYK/qhkwRx7/rF7J7ibGsdrPT+3nHLSu
BqzCCth4YYs+TG7Tp8f/RpvHyc2mg+bb9ZHGug0tW9a2X2I6J0Wqp67EN8oSpW1Hn1OZwdrm7cRs
pertnd2Nb2/tbRKg+4xVkUbEaqp+FAQ+am+X7TT3ix2CrUwh0/5FUnO7tWU41Su0ww3bNku16qj6
L/8Dr1WYmXwUAAA=
headers:
access-control-allow-origin: ['*']
access-control-expose-headers: ['ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit,
X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes,
X-Poll-Interval']
cache-control: ['private, max-age=60, s-maxage=60']
content-encoding: [gzip]
content-security-policy: [default-src 'none']
content-type: [application/json; charset=utf-8]
date: ['Sun, 15 Jul 2018 22:25:30 GMT']
etag: [W/"4e2c4803d93792997d5710f373e899cd"]
referrer-policy: ['origin-when-cross-origin, strict-origin-when-cross-origin']
server: [GitHub.com]
status: [200 OK]
strict-transport-security: [max-age=31536000; includeSubdomains; preload]
vary: ['Accept, Authorization, Cookie, X-GitHub-OTP']
x-content-type-options: [nosniff]
x-frame-options: [deny]
x-github-media-type: [github.v3; param=full; format=json]
x-github-request-id: ['8982:7DB6:A098CD2:147496D3:5B4BC9DA']
x-ratelimit-limit: ['5000']
x-ratelimit-remaining: ['4998']
x-ratelimit-reset: ['1531697130']
x-runtime-rack: ['0.094512']
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
version: 1
22 changes: 20 additions & 2 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,28 @@

from __future__ import absolute_import, division, print_function

import pytest

from github_file.cli import cli

GITHUB_FILE = '''\
[core]
owner = jacquerie
repo = github-file
description = Configure your GitHub repository from a file,
without having to click around in the UI.

[features]
has_issues = true
has_wiki = false
'''


@pytest.mark.vcr()
def test_update_uses_the_provided_filename(runner, tmpdir):
config_fd = tmpdir.join('github-compose.yaml')
config_fd.write(GITHUB_FILE)

def test_update_uses_the_provided_filename(runner):
result = runner.invoke(cli, ['update', '-f', 'Githubfile'])
result = runner.invoke(cli, ['update', '-f', str(config_fd)])

assert 0 == result.exit_code