├── .circleci └── config.yml ├── .gitignore ├── README.md ├── meme.png └── requirements.txt /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | workflows: 2 | version: 2 3 | deploy_meme: 4 | jobs: 5 | - build: 6 | filters: 7 | branches: 8 | ignore: /.*/ 9 | tags: 10 | only: /.*/ 11 | 12 | version: 2 13 | jobs: 14 | build: 15 | docker: 16 | - image: circleci/python:2.7-stretch 17 | environment: 18 | - TITLE: "My Meme" 19 | - SUBREDDIT: "mrpowerscripts" 20 | steps: 21 | - checkout 22 | - restore_cache: 23 | keys: 24 | - v1-dependencies-{{ checksum "requirements.txt" }} 25 | - run: 26 | name: install dependencies 27 | command: | 28 | virtualenv venv 29 | . venv/bin/activate 30 | pip install -r requirements.txt 31 | - save_cache: 32 | paths: 33 | - ./venv 34 | key: v1-dependencies-{{ checksum "requirements.txt" }} 35 | - run: echo "${CIRCLE_COMPARE_URL%/*/*}/tree/${CIRCLE_TAG}/meme.png" > MEME_URL 36 | - run: 37 | name: Meme Time 38 | shell: ./venv/bin/python 39 | command: | 40 | import os, datetime 41 | import imghdr 42 | import praw 43 | from PIL import Image 44 | from imgurpython import ImgurClient 45 | 46 | image_path = os.path.join(os.getcwd(), 'meme.png') 47 | image = Image.open(image_path) 48 | image_width = image.size[0] 49 | image_height = image.size[1] 50 | 51 | if not imghdr.what(image_path) in ['png', 'jpeg']: 52 | raise Exception('Not a valid image type (png or jpeg)') 53 | 54 | if image_width < 500: 55 | raise Exception('What is this a meme for ants? Width too small') 56 | 57 | if image_width > 1000: 58 | raise Exception('Image width is too large!') 59 | 60 | if image_height < 500: 61 | raise Exception('What is this a meme for ants? Height is too small') 62 | 63 | if image_height > 1000: 64 | raise Exception('Image height is too large!') 65 | 66 | imgur = ImgurClient(os.environ['IMGUR_CLIENT_ID'], 67 | os.environ['IMGUR_CLIENT_SECRET']) 68 | 69 | reddit = praw.Reddit(client_id=os.environ['REDDIT_CLIENT_ID'], 70 | client_secret=os.environ['REDDIT_CLIENT_SECRET'], 71 | user_agent='meme-cd', 72 | username=os.environ['REDDIT_USERNAME'], 73 | password=os.environ['REDDIT_PASSWORD']) 74 | 75 | imgur_config = { 76 | 'name': 'Meme', 77 | 'title': os.environ['TITLE'], 78 | 'description': 'My meme uploaded on {0}'.format(datetime.datetime.now()) 79 | } 80 | 81 | try: 82 | imgur_response = imgur.upload_from_path(image_path, 83 | config=imgur_config, anon=False) 84 | except Exception as e: 85 | raise e 86 | 87 | post_config = { 88 | 'title': os.environ['TITLE'], 89 | 'resubmit': True, 90 | 'url': imgur_response['link'] 91 | } 92 | 93 | with open('MEME_URL', 'r') as meme_url_file: 94 | meme_url=meme_url_file.read() 95 | 96 | try: 97 | post = reddit.subreddit(os.environ['SUBREDDIT']).submit(**post_config) 98 | post.reply(""" 99 | This meme was delivered fresh with [continuous meme delivery](https://github.com/mrpowerscripts/meme-cd) 100 | 101 | [View this Meme on GitHub]({meme_url}) 102 | """.format(meme_url=meme_url)) 103 | except Exception as e: 104 | raise e 105 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Continuous Meme Delivery 2 | 3 | [Youtube VIDEO: Continuous Meme Delivery](https://youtu.be/oHaYyZgiDIU) 4 | 5 | ## Probably the most pointless thing I've ever put together 6 | 7 | ### How it works 8 | 9 | Continuous Integration and Continuous Deployment are two software development paradigms 10 | that streamline the process between committing your code changes and making those changes 11 | accessible to your users. Ensuring that your software maintains a high standard of quality by automatically 12 | running all of your tests (lol tests) against every change you make and quickly deploying those changes 13 | when they've passed the quality checks. It is a process now used by every major software development company to ensure that mission critical software is delivered as quickly as possible without unexpected problems arising after deployment. 14 | 15 | This repository uses it to upload a Meme to Reddit. 16 | 17 | There are many CI/CD tools available to use. Travis, Jenkins, Drone.io, Codeship. For this example we will 18 | use CircleCI. 19 | 20 | You can view the builds run by this repository [here on the CircleCI website](https://circleci.com/gh/MrPowerScripts/meme-cd). 21 | 22 | The Meme image is in the root of the repository as `meme.png`. All of the magic occurs inside of the config.yml. It contains the instructions that perform some basic testing on the image, uploading that image to Imgur, and then posting it as a link post to a subreddit. 23 | 24 | Imgur, Reddit, and Github accounts are of course required. Also registering an application on Imgur and Reddit so that we can use their API. 25 | 26 | Registering an Imgur app can be done here https://api.imgur.com/oauth2/addclient 27 | 28 | Registering a Reddit app can be done here https://www.reddit.com/prefs/apps/ 29 | 30 | Once you've registered your apps you'll be given a client_id and client_secret. These details 31 | are added into the CircleCI website as environment variables, so that we don't expose them in the repository. Reddit also requires that you include your reddit username and password for write access. 32 | 33 | [This two minute video](https://www.youtube.com/watch?v=KhjwnTD4oec) shows how to setup the 34 | meme-cd repository to your CircleCI account so that you can add the Environment Variables, 35 | 36 | Adding environment variables for the project on CircleCI can be done here 37 | (note to change the username to your GitHub username) 38 | https://circleci.com/gh/mrpowerscripts/meme-cd/edit#env-vars 39 | 40 | The required enviroment variables to set in CircleCI are: 41 | ``` 42 | IMGUR_CLIENT_ID 43 | IMGUR_CLIENT_SECRET 44 | REDDIT_CLIENT_ID 45 | REDDIT_CLIENT_SECRET 46 | REDDIT_USERNAME 47 | REDDIT_PASSWORD 48 | ``` 49 | 50 | Once all that is set up you can deploy a Meme to the subreddit of your choosing by editing the additional Environment Variables set near the top of the config.yml. You can edit the TITLE to choose 51 | the name of your post. 52 | 53 | ``` 54 | environment: 55 | - TITLE: "My Meme" 56 | - SUBREDDIT: "mrpowerscripts" 57 | ``` 58 | 59 | The config.yml is set to only run a deployment when you push a tag. So you can manage different 60 | Memes in different branches and push them without accidentally deploying. When you want to deploy a Meme simply create a tag `git tag my-meme` and push it up to your repository. This will run some basic checks on the image and then perform the deployment. 61 | -------------------------------------------------------------------------------- /meme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrPowerScripts/meme-cd/216040eef95dee7f1d9a0a4a046fbb18179eff9d/meme.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2017.11.5 2 | chardet==3.0.4 3 | idna==2.6 4 | imgurpython==1.1.7 5 | olefile==0.44 6 | Pillow==4.3.0 7 | pkg-resources==0.0.0 8 | praw==5.3.0 9 | prawcore==0.13.0 10 | requests==2.18.4 11 | update-checker==0.16 12 | urllib3==1.22 13 | --------------------------------------------------------------------------------