Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/gruntworker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Rebert <github@rebertia.com>2014-11-11 05:12:42 +0300
committerChris Rebert <code@rebertia.com>2014-12-03 11:05:33 +0300
commita4a2ccf36c63c9416d40c87c7f0bf60e22a1d91c (patch)
treeea5c2df6e2c8402ba55740181074eecf632cd73a
parent39fa648ccdddeb7d7efbb3192b71fa6e29b895c4 (diff)
v3
-rw-r--r--.gitattributes8
-rw-r--r--.gitignore54
-rw-r--r--.travis.yml3
-rw-r--r--Dockerfile40
-rw-r--r--LICENSE.txt (renamed from LICENSE)2
-rw-r--r--gruntworker.crontab1
-rwxr-xr-xgruntworker.py136
-rwxr-xr-xgruntworker.sh2
-rwxr-xr-xsetup_droplet.sh26
9 files changed, 271 insertions, 1 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a97ce0b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,8 @@
+# Enforce Unix newlines
+*.conf text eol=lf
+*.sbt text eol=lf
+*.scala text eol=lf
+*.sh text eol=lf
+*.md text eol=lf
+*.txt text eol=lf
+*.yml text eol=lf
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..db4561e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,54 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..3f0bc12
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,3 @@
+language: scala
+scala:
+ - 2.10.4
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..906a003
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,40 @@
+# Written against Docker v1.3.1
+FROM node:0.10
+MAINTAINER Chris Rebert <code@rebertia.com>
+
+WORKDIR /
+
+ENV DEBIAN_FRONTEND noninteractive
+RUN ["apt-get", "update"]
+RUN ["apt-get", "-y", "install", "apt-utils"]
+RUN ["apt-get", "-y", "--no-install-recommends", "install", "build-essential", "openssh-client", "git", "python3", "python3-dev"]
+# Grunt
+RUN ["npm", "install", "-g", "grunt-cli"]
+
+RUN ["useradd", "gruntworker"]
+
+ADD gruntworker.py /app/gruntworker.py
+ADD gruntworker.sh /app/gruntworker.sh
+ADD git-repo /git-repo
+
+# Setup SSH keys
+ADD ssh/id_rsa.pub /home/gruntworker/.ssh/id_rsa.pub
+ADD ssh/id_rsa /home/gruntworker/.ssh/id_rsa
+RUN ssh-keyscan -t rsa github.com > /home/gruntworker/.ssh/known_hosts
+
+# Fix permissions
+RUN ["chown", "-R", "gruntworker:gruntworker", "/git-repo"]
+RUN ["chown", "-R", "gruntworker:gruntworker", "/home/gruntworker"]
+# chmod must happen AFTER chown, due to https://github.com/docker/docker/issues/6047
+RUN ["chmod", "-R", "go-rwx", "/home/gruntworker/.ssh"]
+
+USER gruntworker
+WORKDIR /git-repo
+
+RUN ["git", "remote", "set-url", "origin", "https://github.com/twbs/bootstrap.git"]
+RUN ["git", "remote", "set-url", "--push", "origin", "git@github.com:twbs/bootstrap.git"]
+RUN ["git", "config", "user.name", "Bootstrap's Grunt bot"]
+RUN ["git", "config", "user.email", "gruntworker@getbootstrap.com"]
+RUN ["npm", "install"]
+
+ENTRYPOINT ["/app/gruntworker.sh"]
diff --git a/LICENSE b/LICENSE.txt
index 68f3e1f..272e828 100644
--- a/LICENSE
+++ b/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2014 Chris Rebert
+Copyright (c) 2014 Christopher Rebert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/gruntworker.crontab b/gruntworker.crontab
new file mode 100644
index 0000000..9380831
--- /dev/null
+++ b/gruntworker.crontab
@@ -0,0 +1 @@
+*/10 * * * * gruntworker docker run gruntworker
diff --git a/gruntworker.py b/gruntworker.py
new file mode 100755
index 0000000..297710c
--- /dev/null
+++ b/gruntworker.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+# coding=utf-8
+
+from sys import exit
+from os import devnull as DEV_NULL
+from subprocess import check_call, check_output, CalledProcessError
+from shutil import rmtree
+from datetime import datetime
+
+
+def log(*args):
+ now = datetime.now().replace(microsecond=0).isoformat(' ')
+ print(now, "gruntworker: ", end='')
+ print(*args, flush=True)
+
+
+def run_expecting_success(cmd):
+ log("\trunning:", b' '.join(cmd).decode('utf8', 'replace'))
+ with open(DEV_NULL) as void:
+ check_call(cmd, stdin=void)
+
+
+def run_for_output(cmd):
+ log("\trunning:", b' '.join(cmd).decode('utf8', 'replace'))
+ return check_output(cmd, input=b'')
+
+
+def reset_to_master_and_die():
+ log("Attempting to reset current checkout & branch to local master...")
+ try:
+ run_expecting_success([b'git', b'checkout', b'-f', b'master'])
+ except CalledProcessError:
+ log("Error forcibly checking out master; Failed!")
+ exit(1)
+
+
+def fetch_origin():
+ log("Fetching from origin...")
+ try:
+ run_expecting_success([b'git', b'fetch', b'origin', b'+master'])
+ except CalledProcessError:
+ log("Error fetching from origin; Failed!")
+ exit(1)
+
+
+def update_master(to_commitish=b'FETCH_HEAD'):
+ log("Setting local master to {0}...".format(to_commitish.decode('utf8', 'replace')))
+ try:
+ run_expecting_success([b'git', b'checkout', b'-f', to_commitish])
+ run_expecting_success([b'git', b'branch', b'-f', b'master', to_commitish])
+ run_expecting_success([b'git', b'checkout', b'-f', b'master'])
+ except CalledProcessError:
+ log("Error setting local master to {0}!".format(to_commitish))
+ reset_to_master_and_die()
+
+
+def update_npm():
+ try:
+ log("Pruning unnecessary npm modules...")
+ run_expecting_success([b'npm', b'prune'])
+ log("Installing/updating npm modules per package.json ...")
+ run_expecting_success([b'npm', b'install'])
+ except CalledProcessError:
+ log("Error performing npm operations!")
+ log("Purging node_modules due to errors.")
+ try:
+ rmtree('./node_modules', ignore_errors=True)
+ except (IOError, OSError) as io_err:
+ log("Error purging node_modules: {!r}".format(io_err))
+ else:
+ log("Successfully purged node_modules.")
+ log("Failed!")
+ exit(1)
+
+
+def get_head_commit_sha():
+ commit_sha = run_for_output([b'git', b'rev-parse', b'HEAD']).strip()
+ if len(commit_sha) != 40:
+ log("Got malformed commit SHA for HEAD:", commit_sha.decode('utf8'))
+ log("Exiting due to insanity; Failed!")
+ exit(1)
+ return commit_sha
+
+
+def grunt_or_err():
+ log("Grunting...")
+ try:
+ run_expecting_success([b'grunt', b'dist'])
+ except CalledProcessError:
+ log("Error while grunting!")
+ raise
+
+
+def get_modified_files():
+ output = run_for_output([b'git', b'status', b'-z', b'-uno', b'--ignore-submodules=all'])
+ lines = output.split(b'\x00')
+ return [line[3:] for line in lines if line[:2] == b' M']
+
+
+def push_or_err():
+ log("Pushing to origin...")
+ try:
+ run_expecting_success([b'git', b'push', b'origin', b'master'])
+ except CalledProcessError:
+ log("Error pushing to origin!")
+ raise
+
+
+def main():
+ orig_commit_sha = get_head_commit_sha()
+ fetch_origin()
+ update_master()
+ post_fetch_commit_sha = get_head_commit_sha()
+ if post_fetch_commit_sha == orig_commit_sha:
+ log("Fetch didn't change HEAD commit; Done.")
+ return
+ update_npm()
+ try:
+ grunt_or_err()
+ modified_files = get_modified_files()
+ if not modified_files:
+ log("No files modified by grunt; Done.")
+ return
+ run_expecting_success([b'git', b'add', b'--'] + modified_files)
+ run_expecting_success([b'git', b'commit', b'-m', b"automatic grunt dist"])
+ push_or_err()
+ except Exception:
+ log("Resetting master branch & checkout back to commit {} ...".format(post_fetch_commit_sha))
+ update_master(to_commitish=post_fetch_commit_sha)
+ log("Failed!")
+ else:
+ log("Successfully pushed changes; Done.")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/gruntworker.sh b/gruntworker.sh
new file mode 100755
index 0000000..04dedd8
--- /dev/null
+++ b/gruntworker.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+flock -xn /var/lock/gruntworker /app/gruntworker.py
diff --git a/setup_droplet.sh b/setup_droplet.sh
new file mode 100755
index 0000000..92c7752
--- /dev/null
+++ b/setup_droplet.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Step 0.0: Put SSH keys in ./ssh
+# Step 0.1: Checkout git repo to ./git-repo
+
+set -e -x
+
+# set to Pacific Time (for @cvrebert)
+# ln -sf /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
+
+# remove useless crap
+aptitude remove wpasupplicant wireless-tools
+aptitude remove pppconfig pppoeconf ppp
+
+# setup firewall
+ufw default allow outgoing
+ufw default deny incoming
+ufw allow ssh
+ufw allow www # not necessary for gruntworker itself
+ufw enable
+ufw status verbose
+
+# setup Docker; written against Docker v1.2.0
+docker rmi gruntworker
+docker build --tag gruntworker . 2>&1 | tee docker.build.log
+cp ./gruntworker.crontab /etc/cron.d/gruntworker
+restart cron # until upstart goes away