It's wrangler-action 1.1.0! 📡

- Support `apiToken` as an authentication method
  - Deprecates `apiKey` and `email`, making them optional parameters and encouraging `apiToken` usage in build logs
- Support `wranglerVersion` for installing a specific Wrangler version for your build
- Per #7, support for `workingDirectory` to run `wrangler-action` in a specific directory in your repo
- Adds a test Workers project under the `test` directory. This is used in the repo's new set of workflows (see below)
- Adds a GitHub Action workflow that:
  - Lints `entrypoint.sh` to ensure that the shell script looks correct
  - Runs the action with various config options to ensure future pushes don't introduce regressions
This commit is contained in:
Kristian Freeman 2019-11-22 10:27:40 -06:00
parent 2360296525
commit 9e7e2ec6db
11 changed files with 272 additions and 49 deletions

33
.github/workflows/deploy.yml vendored Normal file
View file

@ -0,0 +1,33 @@
on: push
jobs:
deploy:
runs-on: ubuntu-latest
name: Deploy
steps:
- uses: actions/checkout@master
- name: Lint shell script
uses: azohra/shell-linter@v0.1.0
with:
path: "entrypoint.sh"
- name: Publish app with api token
uses: signalnerve/wrangler-action@1.1.0
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
environment: "production"
workingDirectory: 'test'
- name: Publish app with legacy credentials
uses: signalnerve/wrangler-action@1.1.0
with:
apiKey: ${{ secrets.CLOUDFLARE_API_KEY }}
email: ${{ secrets.CLOUDFLARE_EMAIL }}
environment: "production"
workingDirectory: 'test'
- name: Publish app with hardcoded Wrangler version
uses: signalnerve/wrangler-action@1.1.0
with:
apiKey: ${{ secrets.CLOUDFLARE_API_KEY }}
email: ${{ secrets.CLOUDFLARE_EMAIL }}
environment: "production"
wranglerVersion: '1.5.0'
workingDirectory: 'test'

View file

@ -21,52 +21,75 @@ jobs:
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Publish - name: Publish
uses: cloudflare/wrangler-action@1.0.0 uses: cloudflare/wrangler-action@1.1.0
with: with:
apiKey: ${{ secrets.CF_API_KEY }} apiToken: ${{ secrets.CF_API_TOKEN }}
email: ${{ secrets.CF_EMAIL }}
``` ```
## Configuration ## Authentication
You'll need to configure Wrangler using GitHub's Secrets feature - go to "Settings -> Secrets" and add your Cloudflare API key and email (for help finding these, see the [Workers documentation](https://developers.cloudflare.com/workers/quickstart/#finding-your-cloudflare-api-keys)). Your API key and email are encrypted by GitHub, and the action won't print them into logs, so they should be safe! You'll need to configure Wrangler using GitHub's Secrets feature - go to "Settings -> Secrets" and add your Cloudflare API token (for help finding this, see the [Workers documentation](https://developers.cloudflare.com/workers/quickstart/#api-token)). Your API token is encrypted by GitHub, and the action won't print it into logs, so it should be safe!
With your API key and email set as secrets for your repository, pass them to the action in the `with` block of your workflow. Below, I've set the secret names to `CF_API_KEY` and `CF_EMAIL`: With your API token set as a secret for your repository, pass it to the action in the `with` block of your workflow. Below, I've set the secret name to `CF_API_TOKEN`:
```yaml ```yaml
jobs: jobs:
deploy: deploy:
name: Deploy name: Deploy
steps: steps:
uses: cloudflare/wrangler-action@1.0.0 uses: cloudflare/wrangler-action@1.1.0
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
```
`wrangler-action` also supports using your [global API key and email](https://developers.cloudflare.com/workers/quickstart/#global-api-key) as an authentication method, although API tokens are preferred. Pass in `apiKey` and `email` to the GitHub Action to use this method:
```yaml
jobs:
deploy:
name: Deploy
steps:
uses: cloudflare/wrangler-action@1.1.0
with: with:
apiKey: ${{ secrets.CF_API_KEY }} apiKey: ${{ secrets.CF_API_KEY }}
email: ${{ secrets.CF_EMAIL }} email: ${{ secrets.CF_EMAIL }}
``` ```
Optionally, you can also pass an `environment` key to the action. If you're using Wrangler's [environments](https://github.com/cloudflare/wrangler/blob/master/docs/content/environments.md) feature, you can customize _where_ the action deploys to by passing the matching environment in the `with` block of your workflow: ## Configuration
If you're using Wrangler's [environments](https://github.com/cloudflare/wrangler/blob/master/docs/content/environments.md) feature, you can customize _where_ the action deploys to by passing an `environment` in the `with` block of your workflow:
```yaml ```yaml
jobs: jobs:
deploy: deploy:
# ... previous configuration ...
steps: steps:
uses: cloudflare/wrangler-action@1.0.0 uses: cloudflare/wrangler-action@1.1.0
with: with:
# ... api key and email ... apiToken: ${{ secrets.CF_API_TOKEN }}
environment: 'production' environment: 'production'
``` ```
If you need to install a specific version of Wrangler to use for deployment, you can also pass the input `wranglerVersion` to install a specific version of Wrangler from NPM. This should be a [SemVer](https://semver.org/)-style version number, such as `1.6.0`:
```yaml
jobs:
deploy:
steps:
uses: cloudflare/wrangler-action@1.1.0
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
wranglerVersion: '1.6.0'
```
Optionally, you can also pass a `workingDirectory` key to the action. This will allow you to specify a subdirectory of the repo to run the Wrangler command from. Optionally, you can also pass a `workingDirectory` key to the action. This will allow you to specify a subdirectory of the repo to run the Wrangler command from.
```yaml ```yaml
jobs: jobs:
deploy: deploy:
# ... previous configuration ...
steps: steps:
uses: cloudflare/wrangler-action@1.0.0 uses: cloudflare/wrangler-action@1.1.0
with: with:
# ... api key and email ... apiToken: ${{ secrets.CF_API_TOKEN }}
workingDirectory: 'subfoldername' workingDirectory: 'subfoldername'
``` ```
@ -89,10 +112,9 @@ jobs:
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Publish - name: Publish
uses: cloudflare/wrangler-action@1.0.0 uses: cloudflare/wrangler-action@1.1.0
with: with:
apiKey: ${{ secrets.CF_API_KEY }} apiToken: ${{ secrets.CF_API_TOKEN }}
email: ${{ secrets.CF_EMAIL }}
``` ```
Note that there are a number of possible events, like `push`, that can be used to trigger a workflow. For more details on the events available, check out the [GitHub Actions documentation](https://help.github.com/en/articles/workflow-syntax-for-github-actions#on). Note that there are a number of possible events, like `push`, that can be used to trigger a workflow. For more details on the events available, check out the [GitHub Actions documentation](https://help.github.com/en/articles/workflow-syntax-for-github-actions#on).
@ -113,10 +135,9 @@ jobs:
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Publish app - name: Publish app
uses: cloudflare/wrangler-action@1.0.0 uses: cloudflare/wrangler-action@1.1.0
with: with:
apiKey: ${{ secrets.CF_API_KEY }} apiToken: ${{ secrets.CF_API_TOKEN }}
email: ${{ secrets.CF_EMAIL }}
``` ```
If you need help defining the correct cron syntax, check out [crontab.guru](https://crontab.guru/), which provides a friendly user interface for validating your cron schedule. If you need help defining the correct cron syntax, check out [crontab.guru](https://crontab.guru/), which provides a friendly user interface for validating your cron schedule.
@ -136,10 +157,9 @@ jobs:
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Publish app - name: Publish app
uses: cloudflare/wrangler-action@1.0.0 uses: cloudflare/wrangler-action@1.1.0
with: with:
apiKey: ${{ secrets.CF_API_KEY }} apiToken: ${{ secrets.CF_API_TOKEN }}
email: ${{ secrets.CF_EMAIL }}
``` ```
To make the GitHub API request, you can deploy a custom [Cloudflare Workers](https://workers.cloudflare.com) function, which will send a `POST` request to GitHub's API and trigger a new deploy: To make the GitHub API request, you can deploy a custom [Cloudflare Workers](https://workers.cloudflare.com) function, which will send a `POST` request to GitHub's API and trigger a new deploy:
@ -188,8 +208,7 @@ jobs:
- name: Build site - name: Build site
run: 'npm run build' run: 'npm run build'
- name: Publish - name: Publish
uses: cloudflare/wrangler-action@1.0.0 uses: cloudflare/wrangler-action@1.1.0
with: with:
apiKey: ${{ secrets.CF_API_KEY }} apiToken: ${{ secrets.CF_API_TOKEN }}
email: ${{ secrets.CF_EMAIL }}
``` ```

View file

@ -8,12 +8,14 @@ runs:
image: 'Dockerfile' image: 'Dockerfile'
inputs: inputs:
apiKey: apiKey:
description: "Your Cloudflare API Key" description: "(Legacy) Your Cloudflare API Key"
required: true apiToken:
description: "Your Cloudflare API Token"
email: email:
description: "Your Cloudflare Email" description: "(Legacy) Your Cloudflare Email"
required: true
environment: environment:
description: "The environment you'd like to publish your Workers project to - must be defined in wrangler.toml" description: "The environment you'd like to publish your Workers project to - must be defined in wrangler.toml"
workingDirectory: workingDirectory:
description: "The relative path which Wrangler commands should be run from" description: "The relative path which Wrangler commands should be run from"
wranglerVersion:
description: "The version of Wrangler you'd like to use to publish your Workers project"

View file

@ -6,35 +6,71 @@ export HOME="/github/workspace"
export NVM_DIR="/github/workspace/nvm" export NVM_DIR="/github/workspace/nvm"
export WRANGLER_HOME="/github/workspace" export WRANGLER_HOME="/github/workspace"
# h/t https://github.com/elgohr/Publish-Docker-Github-Action
sanitize() {
if [ -z "${1}" ]
then
>&2 echo "Unable to find ${2}. Did you add a GitHub secret called key ${2}, and pass in secrets.${2} in your workflow?"
exit 1
fi
}
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.0/install.sh | bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.0/install.sh | bash
# Comments beginning with "shellcheck" use shellcheck, a shell script linter.
# The below comments ignore shellcheck linting on the instructions provided
# by NVM.
# shellcheck source=/dev/null
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# shellcheck source=/dev/null
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
mkdir -p "$HOME/.wrangler" mkdir -p "$HOME/.wrangler"
chmod -R 770 "$HOME/.wrangler" chmod -R 770 "$HOME/.wrangler"
sanitize "${INPUT_EMAIL}" "email" export API_CREDENTIALS=""
sanitize "${INPUT_APIKEY}" "apiKey"
export CF_EMAIL="$INPUT_EMAIL" # If an API token is detected as input
export CF_API_KEY="$INPUT_APIKEY" if [ -n "$INPUT_APITOKEN" ]
npm i @cloudflare/wrangler -g
if ! [ -z "$INPUT_WORKINGDIRECTORY" ]
then then
cd $INPUT_WORKINGDIRECTORY export CF_API_TOKEN="$INPUT_APITOKEN"
export API_CREDENTIALS="API Token"
fi fi
# If an API key and email are detected as input
if [ -n "$INPUT_APIKEY" ] && [ -n "$INPUT_EMAIL" ]
then
export CF_EMAIL="$INPUT_EMAIL"
export CF_API_KEY="$INPUT_APIKEY"
export API_CREDENTIALS="Email and API Key"
fi
if [ -n "$INPUT_APIKEY" ] && [ -z "$INPUT_EMAIL" ]
then
echo "Provided an API key without an email for authentication. Please pass in 'apiKey' and 'email' to the action."
fi
if [ -z "$INPUT_APIKEY" ] && [ -n "$INPUT_EMAIL" ]
then
echo "Provided an email without an API key for authentication. Please pass in 'apiKey' and 'email' to the action."
exit 1
fi
if [ -z "$API_CREDENTIALS" ]
then
>&2 echo "Unable to find authentication details. Please pass in an 'apiToken' as an input to the action, or a legacy 'apiKey' and 'email'."
exit 1
else
echo "Using $API_CREDENTIALS authentication"
fi
# If a Wrangler version is detected as input
if [ -z "$INPUT_WRANGLERVERSION" ]
then
npm i @cloudflare/wrangler -g
else
npm i "@cloudflare/wrangler@$INPUT_WRANGLERVERSION" -g
fi
# If a working directory is detected as input
if [ -n "$INPUT_WORKINGDIRECTORY" ]
then
cd "$INPUT_WORKINGDIRECTORY"
fi
# If an environmentdirectory is detected as input
if [ -z "$INPUT_ENVIRONMENT" ] if [ -z "$INPUT_ENVIRONMENT" ]
then then
wrangler publish wrangler publish
@ -42,7 +78,9 @@ else
wrangler publish -e "$INPUT_ENVIRONMENT" wrangler publish -e "$INPUT_ENVIRONMENT"
fi fi
if ! [ -z "$INPUT_WORKINGDIRECTORY" ] # If a working directory is detected as input, revert to the
# original directory before continuing with the workflow
if [ -n "$INPUT_WORKINGDIRECTORY" ]
then then
cd $HOME cd $HOME
fi fi

1
test/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
dist

6
test/public/index.html Normal file
View file

@ -0,0 +1,6 @@
<h1>My Static Site Test</h1>
<p>This is the content of my site</p>
<footer>
And this is my footer
</footer>

View file

View file

@ -0,0 +1,80 @@
import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'
/**
* The DEBUG flag will do two things that help during development:
* 1. we will skip caching on the edge, which makes it easier to
* debug.
* 2. we will return an error message on exception in your Response rather
* than the default 404.html page.
*/
const DEBUG = false
addEventListener('fetch', event => {
try {
event.respondWith(handleEvent(event))
} catch (e) {
if (DEBUG) {
return event.respondWith(
new Response(e.message || e.toString(), {
status: 500,
}),
)
}
event.respondWith(new Response('Internal Error', { status: 500 }))
}
})
async function handleEvent(event) {
const url = new URL(event.request.url)
let options = {}
/**
* You can add custom logic to how we fetch your assets
* by configuring the function `mapRequestToAsset`
*/
// options.mapRequestToAsset = handlePrefix(/^\/docs/)
try {
if (DEBUG) {
// customize caching
options.cacheControl = {
bypassCache: true,
}
}
return await getAssetFromKV(event, options)
} catch (e) {
// if an error is thrown try to serve the asset at 404.html
if (!DEBUG) {
try {
let notFoundResponse = await getAssetFromKV(event, {
mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req),
})
return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 })
} catch (e) {}
}
return new Response(e.message || e.toString(), { status: 500 })
}
}
/**
* Here's one example of how to modify a request to
* remove a specific prefix, in this case `/docs` from
* the url. This can be useful if you are deploying to a
* route on a zone, or if you only want your static content
* to exist at a specific path.
*/
function handlePrefix(prefix) {
return request => {
// compute the default (e.g. / -> index.html)
let defaultAssetKey = mapRequestToAsset(request)
let url = new URL(defaultAssetKey.url)
// strip the prefix from the path for lookup
url.pathname = url.pathname.replace(prefix, '/')
// inherit all other props from the default request
return new Request(url.toString(), defaultAssetKey)
}
}

21
test/workers-site/package-lock.json generated Normal file
View file

@ -0,0 +1,21 @@
{
"name": "worker",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@cloudflare/kv-asset-handler": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.0.5.tgz",
"integrity": "sha512-7yLMAUZD1XQNKzmktYCcUUPB+wXmQENv1MMi8QEMs0rzL01e0XEyCUUDauRXHzxi7dBbSUGA5RS23h890ncKog==",
"requires": {
"mime": "^2.4.4"
}
},
"mime": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
"integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA=="
}
}
}

View file

@ -0,0 +1,12 @@
{
"private": true,
"name": "worker",
"version": "1.0.0",
"description": "A template for kick starting a Cloudflare Workers project",
"main": "index.js",
"author": "Ashley Lewis <ashleymichal@gmail.com>",
"license": "MIT",
"dependencies": {
"@cloudflare/kv-asset-handler": "^0.0.5"
}
}

11
test/wrangler.toml Normal file
View file

@ -0,0 +1,11 @@
name = "static-test"
type = "webpack"
workers_dev = true
account_id = "dc56444c4c955a1653106ccf997c1067"
[env.production]
name = "static-test-prod"
[site]
bucket = "./public"
entry-point = "workers-site"