[Git + mac]: Schedule your git commands with launchd
git
mac
03/21/2020
launchd
In computing, launchd, a unified operating system service management framework, starts, stops and manages daemons, applications, processes, and scripts in macOS. It was introduced with Mac OS X Tiger and is licensed under the Apache License — Wikipedia
Scenario Example
You have completed a new release for your project that should be pushed to your GitHub repository at 11:11AM tomorrow. But for some reason, you won't be able to be sitting in front of your computer to upload your release. Let's see how we can schedule to run a program (script) while you're away.
Write a script that needs to be run at a certain time
~/Desktop/push_release.sh
cd ~/Desktop/projectgit add .git commit -m "[RELEASE]: 1.0.1"git push
If you want to create a log file as a result, you can put output to file
cd ~/Desktop/projectgit add .git commit -m "[RELEASE]: 1.0.1" > /tmp/commit_log 2>&1git push > /tmp/push_log 2>&1
2&>1
indicates that standard error is redirected to specified file
(optional): you can choose to make *.sh
executable with chmod +x *.md
, then you won't have to specify bash
in ProgramArguments in plist file below.
Create plist to trigger program to run at a specific time
Make sure to place it under ~/Library/LaunchAgents
. ~
denotes home directory.
~/Library/LaunchAgents/com.launchd.example.plist
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"> <dict> <key>Label</key> <string>com.launchd.example</string> <key>ProgramArguments</key> <array> <string>bash</string> <!-- This line isn't required if *.sh is already executable --> <string>/Users/Me/Desktop/push_release.sh</string> </array> <key>StartCalendarInterval</key> <dict> <key>Month</key> <integer>3</integer> <key>Day</key> <integer>22</integer> <key>Hour</key> <integer>11</integer> <key>Minute</key> <integer>11</integer> </dict> </dict></plist>
Runs
bash /Users/Me/Desktop/push_release.sh
on3/22 at 11:11AM
Please read More about launchd to learn more details
Load launchd
You need to load the plist file after it's created.
launchctl load com.launchd.example.plist
To verify that it's loaded
launchctl list | grep com.launchd.example- 0 com.lanchd.example
Receiving output, i.e.
- 0 com.launchd.example
means that the job is currently loaded
-
: means that it is loaded but is not running
0
means job finished successfully. Any positive number means that there was an error, and negative number denotes a termination
To unload the job
launchctl unload com.launchd.example.plist
Be Aware..
Loaded launchd will still work with Terminal.app closed, but it won't work while your computer is asleep or shutdown.
If it wakes up before the job was executed, or there is more job to be executed, it will continue to work without having to "re-loading" the job
If it wakes up after invocation time period time, and there is no more job to run, it won't re-execute
One workaround can be waking up the mac a few minutes before execution time by going to
Preference
>>Energy Saver
>>Schedule
More about launchd
Directory
Below describes each directory where you can choose to place your plist scripts
Type | Location | Who Runs |
---|---|---|
User Agents* | ~/Library/LaunchAgents | Currently signed in user |
Global Daemons | /Library/LaunchDaemons (Use sudo to edit files) | Currently signed in user |
Global Agents | /Library/LaunchAgents (Use sudo to edit files) | root or specified user with Username key |
In short, place the property list under
~/Library/LaunchAgents
for user specific jobs, under/Library/LaunchAgents
for jobs needed for every user, and under/Library/LaunchDaemons
to run, for example, daily maintenance tasks.
plist Skeleton
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"> <dict> <key>Label</key> <string>com.launchd.example</string> <key>Program</key> <string>/Users/Me/Desktop/push_release.sh</string> <key>RunAtLoad</key> <true/> </dict></plist>
Label
Label
is required for every job and should be unique.
<key>Label</key><string>com.launchd.example</string>
What to Start
ProgramArgument
defines the path to the program
<key>ProgramArgument</key><array> <string>mv</string> <string>/Users/Me/Desktop/push_release.sh</string></array>
When to Start
RunAtLoad
& <true/>
starts the job as soon as the script gets loaded
<key>RunAtLoad</key><true/>
StartInterval
is like a timer. This will run the job every 3600 seconds, every hour, after the script is loaded. The timer stops when computer is asleep.
<key>StartInterval</key><integer>3600</integer>
StartCalendarInterval
lets you to specify time to run the program. The below example will run the program everyday at 11:11PM
<key>StartCalendarInterval</key><dict> <key>Hour</key> <integer>23</integer> <key>Minute</key> <integer>11</integer></dict>
Available Keys:
Month
(1..12),Day
(1..31),Weekday
(0(Sunday)..7(Sunday)),Hour
(0..23),Minute
(0..59)
Below example will run once an hour
<key>StartCalendarInterval</key><dict> <key>Hour</key> <integer>1</integer></dict>
You can use <array>
to define multiple calendar intervals
<key>StartCalendarInterval</key><array> <dict> <key>Hour</key> <integer>23</integer> <key>Minute</key> <integer>11</integer> </dict> <dict> <key>Minute</key> <integer>0</integer> <key>Weekday</key> <integer>7</integer> </dict></array>
Run at 11:11PM every day and every hour on Sundays
- [Git]: Authenticate GitHub Account with SSH Key (macOS, Linux)
- [Git + cron]: Schedule your git commands on AWS EC2