Skip to content

Commit e2f269c

Browse files
Merge pull request #7 from hammerstonedev/af-github-actions
GitHub Actions Driver
2 parents b6207bc + 46f7967 commit e2f269c

File tree

7 files changed

+166
-38
lines changed

7 files changed

+166
-38
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
## Unreleased
44

5-
- Add Hash command
5+
- Add `airdrop:hash` command.
6+
- Add GitHub Actions driver.
67

78
## 0.1.0 - 2021-05-16
89

config/airdrop.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22

33
use Hammerstone\Airdrop\Drivers\FilesystemDriver;
4+
use Hammerstone\Airdrop\Drivers\GithubActionsDriver;
45
use Hammerstone\Airdrop\Triggers\ConfigTrigger;
56
use Hammerstone\Airdrop\Triggers\FileTrigger;
67

@@ -24,6 +25,19 @@
2425
// Used to build up the ZIP file before stashing it.
2526
'local_tmp_directory' => env('AIRDROP_LOCAL_TMP_DIR', storage_path('framework')),
2627

28+
// The skip file is an empty file that will be created to
29+
// indicate that asset building can be skipped.
30+
'skip_file' => env('AIRDROP_SKIP_FILE', base_path('.airdrop_skip')),
31+
],
32+
33+
'github' => [
34+
// Use in conjunction with the Cache step in GitHub Actions.
35+
'class' => GithubActionsDriver::class,
36+
37+
// Make sure this matches the `path` key in the
38+
// cache step of your GitHub Actions Workflow.
39+
'local_tmp_directory' => env('AIRDROP_LOCAL_TMP_DIR', '/tmp/'),
40+
2741
// The skip file is an empty file that will be created to
2842
// indicate that asset building can be skipped.
2943
'skip_file' => env('AIRDROP_SKIP_FILE', base_path('.airdrop_skip')),

docs/drivers/filesystem.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Filesystem Driver
22

3-
The Filesystem Driver is the default (and only!) driver that we ship with. It stores all of your built assets as a `.zip` on a filesystem of your choosing.
3+
The Filesystem Driver is the default driver that we ship with. It stores all of your built assets as a `.zip` on a filesystem of your choosing.
44

55

66
## Configuration
77

88
If you'd like to change the configuration, you can do so in `airdrop.php`.
99

10-
config/aidrop.php{.filename}
10+
config/airdrop.php{.filename}
1111
```php
1212
[
1313
'drivers' => [

docs/drivers/github.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# GitHub Actions Driver
2+
3+
The GitHub Actions driver works as a part of your GitHub Workflows to cache built assets from run to run, even across branches.
4+
5+
When using the GitHub driver, there is _no need_ for a remote disk anywhere. Instead, we rely on the [Cache Action](https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows) to cache the built files for us.
6+
7+
## Configuration
8+
9+
The GitHub driver is an extension of the Filesystem driver so much of the configuration is the same, although fewer items are needed.
10+
11+
config/airdrop.php{.filename}
12+
```php
13+
[
14+
'drivers' => [
15+
'github' => [
16+
// Use in conjunction with the Cache step in GitHub Actions.
17+
'class' => GithubActionsDriver::class,
18+
19+
// Make sure this matches the `path` key in the
20+
// cache step of your GitHub Actions Workflow.
21+
'local_tmp_directory' => env('AIRDROP_LOCAL_TMP_DIR', '/tmp/'),
22+
23+
// The skip file is an empty file that will be created to
24+
// indicate that asset building can be skipped.
25+
'skip_file' => env('AIRDROP_SKIP_FILE', base_path('.airdrop_skip')),
26+
]
27+
],
28+
]
29+
30+
```
31+
32+
`local_tmp_directory` is a place that Airdrop can use to create the `.zip` file before it is uploaded. This needs to match that path that you put in your `[workflow].yml` file.
33+
34+
`skip_file` is the file we referenced in the [deploying](/deploying) section. It's used as a signal to other processes that the built files have been successfully restored, and they do not need to be built again.
35+
36+
## GitHub Workflow Configuration
37+
38+
There are a couple steps you'll need to add to your GitHub Workflow to take advantage of the asset caching.
39+
40+
The first step is to calculate the hash of the inputs and save it in the environment for the cache step to use:
41+
42+
.github/workflows/deploy.yml{.filename}
43+
```yaml
44+
- name: Generate Airdrop Hash
45+
run: echo "AIRDROP_HASH=$(php artisan airdrop:hash)" >> $GITHUB_ENV
46+
```
47+
48+
This command is going to run `php artisan airdrop:hash` to calculate the hash of all the inputs, and then it is going to store it as an environment variable named `AIRDROP_HASH`. This allows the cache step to look for the right key.
49+
50+
The next step you'll need to add is the cache step:
51+
52+
.github/workflows/deploy.yml{.filename}
53+
```yaml
54+
- name: Generate Airdrop Hash
55+
run: echo "AIRDROP_HASH=$(php artisan airdrop:hash)" >> $GITHUB_ENV
56+
57+
- name: Cache Airdrop Assets # [tl! ~~]
58+
uses: actions/cache@v2 # [tl! ~~]
59+
with: # [tl! ~~]
60+
key: ${{ runner.os }}-airdrop-${{ env.AIRDROP_HASH }} # [tl! ~~]
61+
path: /tmp/airdrop-* # [tl! ~~]
62+
```
63+
64+
This step will cache the built zip file from Airdrop, and save it for up to seven days, per GitHub's [usage limits](https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy). (Remember that if a cache misses, your app will simply rebuild the assets!)
65+

docs/manifest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"Drivers": {
1717
"children": {
1818
"Filesystem": "/drivers/filesystem",
19+
"GitHub Actions": "/drivers/github",
1920
"Custom": "/drivers/custom"
2021
}
2122
},

src/Drivers/FilesystemDriver.php

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,27 @@ public function upload()
3737

3838
$this->makeZip($zipPath);
3939

40-
$this->output('Uploading to remote disk at ' . $this->remoteStashPath() . $this->stashedPackageFilename());
40+
$this->uploadToRemoteStorage($zipPath);
41+
}
4142

42-
$this->disk()->putFileAs(
43-
$this->remoteStashPath(),
44-
$zipPath,
45-
$this->stashedPackageFilename()
46-
);
43+
/**
44+
* Called before building files, to see if we can skip that
45+
* altogether and just download them.
46+
*/
47+
public function download()
48+
{
49+
if ($this->extract()) {
50+
$this->output('Assets downloaded and extracted.');
4751

48-
// Clean up after ourselves once it's uploaded.
49-
File::delete($zipPath);
52+
// Touch a file that can be used to inform the deploy
53+
// process that building assets can be skipped.
54+
File::put($this->skipFilePath(), '');
55+
} else {
56+
$this->output('Assets did not exist.');
57+
58+
// Remove the file if extraction did not succeed.
59+
File::delete($this->skipFilePath());
60+
}
5061
}
5162

5263
/**
@@ -74,24 +85,6 @@ public function makeZip($path)
7485
$zip->close();
7586
}
7687

77-
/**
78-
* Called before building files, to see if we can skip that
79-
* altogether and just download them.
80-
*/
81-
public function download()
82-
{
83-
if ($this->extract()) {
84-
$this->output('Assets downloaded and extracted.');
85-
// Touch a file that can be used to inform the deploy
86-
// process that building assets can be skipped.
87-
File::put($this->skipFilePath(), '');
88-
} else {
89-
$this->output('Assets did not exist.');
90-
// Remove the file if extraction did not succeed.
91-
File::delete($this->skipFilePath());
92-
}
93-
}
94-
9588
public function extract()
9689
{
9790
if (!$this->exists()) {
@@ -100,24 +93,20 @@ public function extract()
10093

10194
$zipPath = $this->localStashPath() . $this->stashedPackageFilename();
10295

103-
// Download the file to local disk as a stream.
104-
File::put(
105-
$zipPath,
106-
$this->disk()->readStream($this->remoteStashPath() . $this->stashedPackageFilename())
107-
);
96+
$this->downloadFromRemoteStorage($zipPath);
10897

10998
$zip = new ZipArchive;
11099

111100
$status = $zip->open($zipPath);
112101

113102
if ($status !== true) {
114-
throw new Exception('Airdrop was trying to extract previously built assets, but could not open the zip file at ' . json_encode($zipPath));
103+
throw new Exception(
104+
'Airdrop was trying to extract previously built assets, but could not open the zip file at ' . json_encode($zipPath)
105+
);
115106
}
116107

117108
// Put all the assets back where they should be.
118-
$extracted = $zip->extractTo(base_path());
119-
120-
if (!$extracted) {
109+
if (!$zip->extractTo(base_path())) {
121110
throw new Exception('Zip not extracted');
122111
}
123112

@@ -169,6 +158,36 @@ protected function stashedPackageFilename()
169158
return "airdrop-{$this->hash}.zip";
170159
}
171160

161+
/**
162+
* @param string $zipPath
163+
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
164+
*/
165+
protected function downloadFromRemoteStorage($zipPath)
166+
{
167+
// Download the file to local disk as a stream.
168+
File::put(
169+
$zipPath,
170+
$this->disk()->readStream($this->remoteStashPath() . $this->stashedPackageFilename())
171+
);
172+
}
173+
174+
/**
175+
* @param string $zipPath
176+
*/
177+
protected function uploadToRemoteStorage($zipPath)
178+
{
179+
$this->output('Uploading to remote disk at ' . $this->remoteStashPath() . $this->stashedPackageFilename());
180+
181+
$this->disk()->putFileAs(
182+
$this->remoteStashPath(),
183+
$zipPath,
184+
$this->stashedPackageFilename()
185+
);
186+
187+
// Clean up after ourselves once it's uploaded.
188+
File::delete($zipPath);
189+
}
190+
172191
/**
173192
* @return string
174193
*/
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* @author Aaron Francis <aarondfrancis@gmail.com|https://twitter.com/aarondfrancis>
4+
*/
5+
6+
namespace Hammerstone\Airdrop\Drivers;
7+
8+
class GithubActionsDriver extends FilesystemDriver
9+
{
10+
public function exists()
11+
{
12+
return file_exists($this->localStashPath() . $this->stashedPackageFilename());
13+
}
14+
15+
protected function downloadFromRemoteStorage($zipPath)
16+
{
17+
// For GitHub actions there is no downloading required.
18+
// The file will be placed in the appropriate location
19+
// by the Cache step of the workflow.
20+
}
21+
22+
protected function uploadToRemoteStorage($zipPath)
23+
{
24+
// No upload is required either. GitHub will take the
25+
// zip from the tmp directory and cache it for us for
26+
// later use.
27+
}
28+
}

0 commit comments

Comments
 (0)