Skip to content

Commit

Permalink
feat!: support for setup multiple custom domains (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
adeherysh authored Jan 22, 2025
1 parent 94bcda9 commit 1fba971
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 106 deletions.
19 changes: 8 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Cloudflare Pages Action

Deploy your project to Cloudflare Pages with automatic project creation and custom domain
Deploy your project to Cloudflare Pages with automatic project creation and setup custom domain (with support multiple domain)

## API Token Permissions

* Account Resources:
* Resource: Include -> All Accounts (or spesific account)
* Permissions: Pages -> Edit

* Zone Resources (if using custom domain):
* Zone Resources (if using custom domains):
* Resource: Include -> All Zones (or spesific zone)
* Permissions: Zone -> Read, DNS -> Edit

Expand All @@ -34,7 +34,7 @@ jobs:
run: pnpm build

- name: Deploy
uses: kitabisa/cloudflare-pages-action@v1
uses: kitabisa/cloudflare-pages-action@v2
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
Expand All @@ -43,8 +43,7 @@ jobs:
package-manager: pnpm
build-directory: ./out
project-name: your-cloudflare-project
zone-name: example.com
custom-domain: dev-${{ github.event.pull_request.number }}.example.com
custom-domains: dev-${{ github.event.pull_request.number }}.example.com
working-directory: ./
```
Expand All @@ -68,7 +67,7 @@ jobs:
run: pnpm build

- name: Deploy
uses: kitabisa/cloudflare-pages-action@v1
uses: kitabisa/cloudflare-pages-action@v2
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
Expand All @@ -77,8 +76,7 @@ jobs:
package-manager: pnpm
build-directory: ./out
project-name: your-cloudflare-project
zone-name: example.com
custom-domain: prod.example.com
custom-domains: example.com,example.co.id,example.id
working-directory: ./
```
Expand All @@ -93,13 +91,12 @@ jobs:
| `package-manager` | Setup package manager. | `undefined` | `npm`, `yarn`, `pnpm`, `bun` |
| `build-directory` | Define output build directory. | `undefined` | `./out` |
| `project-name` | Setup project name. | `undefined` | `kitabisa-accounts` |
| `zone-name` | Define Cloudflare zone name. | `""` | `kitabisa.com` |
| `custom-domain` | Setup custom domain. | `""` | `accounts.kitabisa.com` |
| `custom-domains` | Setup custom domains. | `""` | `accounts.kitabisa.com` |
| `working-directory` | Setup working directory. | `"."` | `./apps/accounts` |

## Outputs

| Name | Description | Example |
| ----------------- | --------------------------------------------------------- | ----------------------------- |
| `deployment-url` | The output deployment url from custom domain (if set). | `accounts.kitabisa.com` |
| `deployment-url` | The output deployment url from custom domains (if set). | `accounts.kitabisa.com` |
| `pages-url` | The output deployment url from cloudflare pages. | `kitabisa-accounts.pages.dev` |
122 changes: 27 additions & 95 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Cloudflare Pages Action
description: Deploy your project to Cloudflare Pages with automatic project creation and custom domain
description: Deploy your project to Cloudflare Pages with automatic project creation and setup custom domain (with support multiple domain)
author: Ade Hery Shopyan

branding:
Expand Down Expand Up @@ -42,15 +42,9 @@ inputs:
description: "Set project name"
type: string

zone-name:
custom-domains:
required: false
description: "Set zone name"
default: ""
type: string

custom-domain:
required: false
description: "Set custom domain"
description: "Set custom domains"
default: ""
type: string

Expand All @@ -74,9 +68,7 @@ runs:
steps:
- name: Deploy
id: deploy
# use specific wrangler-action version to handle this issue
# https://github.com/cloudflare/wrangler-action/issues/306
uses: cloudflare/wrangler-action@v3.9.0
uses: cloudflare/wrangler-action@v3
with:
workingDirectory: ${{ inputs.working-directory }}
apiToken: ${{ inputs.api-token }}
Expand All @@ -85,94 +77,34 @@ runs:
command: pages deploy ${{ inputs.build-directory }} --project-name=${{ inputs.project-name }} --branch=${{ inputs.branch }} --commit-dirty=true
packageManager: ${{ inputs.package-manager }}

- name: Get Cloudflare Zone ID
id: get-zone-id
if: "${{ inputs.zone-name != '' }}"
shell: bash
env:
CLOUDFLARE_API_TOKEN: ${{ inputs.api-token }}
ZONE_DOMAIN: ${{ inputs.zone-name }}
run: |
response=$(curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$ZONE_DOMAIN" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json")
zone_id=$(echo $response | jq -r '.result[0].id')
echo "id=$zone_id" >> $GITHUB_OUTPUT
- name: Set Cloudflare DNS Record & Custom Domain
id: dnsrecord
if: "${{ steps.get-zone-id.outputs.id != 'null' && inputs.zone-name != '' && inputs.custom-domain != '' }}"
shell: bash
env:
CLOUDFLARE_API_TOKEN: ${{ inputs.api-token }}
CLOUDFLARE_ACCOUNT_ID: ${{ inputs.account-id }}
CLOUDFLARE_ZONE_ID: ${{ steps.get-zone-id.outputs.id }}
PROJECT_NAME: ${{ inputs.project-name }}
CUSTOM_DOMAIN: ${{ inputs.custom-domain }}
run: |
echo "Check DNS record exist or not for the domain: ${CUSTOM_DOMAIN}"
res_record=$(curl -X GET "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records?type=CNAME&name=$CUSTOM_DOMAIN" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json")
dns_record_id=$(echo $res_record | jq -r '.result[0].id')
if [ "$dns_record_id" == "null" ] || [ -z "$dns_record_id" ]; then
echo "DNS record not found for the domain: ${CUSTOM_DOMAIN}"
response=$(curl -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"type": "CNAME",
"name": "'"$CUSTOM_DOMAIN"'",
"content": "'"$PROJECT_NAME"'.pages.dev",
"ttl": 1,
"proxied": true
}')
id=$(echo $response | jq -r '.result.id')
echo "id=$id" >> $GITHUB_OUTPUT
echo "Set Cloudflare Pages Custom Domain for: ${CUSTOM_DOMAIN}"
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/pages/projects/$PROJECT_NAME/domains" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"name": "'$CUSTOM_DOMAIN'"}'
else
echo "DNS record found for the domain: ${CUSTOM_DOMAIN}"
echo "id=$dns_record_id" >> $GITHUB_OUTPUT
fi
- name: Update Cloudflare DNS Record
if: "${{ steps.get-zone-id.outputs.id != 'null' && inputs.zone-name != '' && inputs.custom-domain != '' && inputs.branch != inputs.production-branch }}"
shell: bash
env:
CLOUDFLARE_API_TOKEN: ${{ inputs.api-token }}
CLOUDFLARE_ZONE_ID: ${{ steps.get-zone-id.outputs.id }}
CUSTOM_DOMAIN: ${{ inputs.custom-domain }}
DNS_RECORD_ID: ${{ steps.dnsrecord.outputs.id }}
PAGES_URL: ${{ steps.deploy.outputs.deployment-url }}
run: |
DNS_RECORD_CONTENT=$(echo "$PAGES_URL" | sed 's/^https:\/\///')
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records/$DNS_RECORD_ID" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"type": "CNAME",
"name": "'"$CUSTOM_DOMAIN"'",
"content": "'"$DNS_RECORD_CONTENT"'",
"id": "'"$DNS_RECORD_ID"'",
"ttl": 1,
"proxied": true
}'
- name: Setup Custom Domains
if: "${{ inputs.custom-domains != '' }}"
uses: kitabisa/cloudflare-pages-action/tools/setup-custom-domains@v2
with:
api-token: ${{ inputs.api-token }}
account-id: ${{ inputs.account-id }}
branch: ${{ inputs.branch }}
production-branch: ${{ inputs.production-branch }}
project-name: ${{ inputs.project-name }}
custom-domains: ${{ inputs.custom-domains }}
deployment-url: ${{ steps.deploy.outputs.deployment-url }}

- name: Get deployment url
id: url
shell: bash
env:
DEPLOYMENT_URL: ${{ inputs.custom-domain }}
PAGES_URL: ${{ steps.deploy.outputs.deployment-url }}
run: |
if [ "$DEPLOYMENT_URL" != "" ]; then
echo "deployment-url=https://$DEPLOYMENT_URL" >> $GITHUB_OUTPUT
PAGES_URL="${{ steps.deploy.outputs.deployment-url }}"
DEPLOYMENT_URL=""
# Check if custom domains are provided
if [ -n "${{ inputs.custom-domains }}" ]; then
# Process the custom domains
DEPLOYMENT_URL=$(echo "${{ inputs.custom-domains }}" | tr ',' '\n' | xargs -I {} echo "https://{}" | tr '\n' ', ' | sed 's/, $//')
fi
# If DEPLOYMENT_URL is not empty, use it; otherwise, fallback to PAGES_URL
if [ -n "$DEPLOYMENT_URL" ]; then
echo "deployment-url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT
echo "pages-url=$PAGES_URL" >> $GITHUB_OUTPUT
else
echo "deployment-url=$PAGES_URL" >> $GITHUB_OUTPUT
Expand Down
134 changes: 134 additions & 0 deletions tools/setup-custom-domains/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
name: Setup Custom Domains
description: Setup Custom Domains

inputs:
api-token:
required: true
description: "Set api token"
type: string

account-id:
required: true
description: "Set account id"
type: string

branch:
required: true
description: "Set branch"
type: string

production-branch:
required: true
description: "Set production branch"
type: string

project-name:
required: true
description: "Set project name"
type: string

custom-domains:
required: true
description: "Set custom domains"
type: string

deployment-url:
required: true
description: "Set deployment url"
type: string

runs:
using: composite
steps:
- name: Setup Custom Domains
shell: bash
env:
CLOUDFLARE_API_TOKEN: ${{ inputs.api-token }}
CLOUDFLARE_ACCOUNT_ID: ${{ inputs.account-id }}
PROJECT_NAME: ${{ inputs.project-name }}
DEPLOYMENT_URL: ${{ inputs.deployment-url }}
BRANCH: ${{ inputs.branch }}
PRODUCTION_BRANCH: ${{ inputs.production-branch }}
run: |
custom_domains=$(echo '${{ inputs.custom-domains }}' | tr -s ' ' ',')
if [ -n "$custom_domains" ]; then
curl -s https://publicsuffix.org/list/public_suffix_list.dat -o public_suffix_list.dat
for domain in $(echo "$custom_domains" | tr ',' '\n'); do
echo "======================================="
echo "Setup custom domain for $domain"
echo "======================================="
tld=""
parts=($(echo "$domain" | tr '.' ' '))
num_parts=${#parts[@]}
for ((i=$num_parts-1; i>=1; i--)); do
suffix=$(echo "${parts[@]:$i}" | tr ' ' '.')
if grep -Fxq "$suffix" public_suffix_list.dat; then
tld=$(echo "${parts[@]:$i}" | tr ' ' '.')
fi
done
tld_parts=($(echo "$tld" | tr '.' ' '))
tld_num_parts=${#tld_parts[@]}
topdomain=$(echo "${parts[$i-$tld_num_parts-1]}.${tld}")
if [ -n "$topdomain" ]; then
echo "======================================="
echo "Get Zone ID from $topdomain"
echo "======================================="
response=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${topdomain}" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json")
zone_id=$(echo $response | jq -r '.result[0].id')
if [ -n "$zone_id" ]; then
res_record=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records?type=CNAME&name=${domain}" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json")
dns_record_id=$(echo $res_record | jq -r '.result[0].id')
if [ "$dns_record_id" == "null" ] || [ -z "$dns_record_id" ]; then
echo "======================================="
echo "Setup DNS Record for $domain"
echo "======================================="
response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"type": "CNAME",
"name": "'"${domain}"'",
"content": "'"$PROJECT_NAME"'.pages.dev",
"ttl": 1,
"proxied": true
}')
dns_record_id=$(echo $response | jq -r '.result.id')
echo "=================================================="
echo "Setup Custom Domain $domain for $PROJECT_NAME"
echo "=================================================="
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/pages/projects/$PROJECT_NAME/domains" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"name": "'${domain}'"}'
fi
if [ "$BRANCH" != "$PRODUCTION_BRANCH" ]; then
echo "=================================================="
echo "Update Deployment on $domain"
echo "=================================================="
deployment_url=$(echo "$DEPLOYMENT_URL" | sed 's/^https:\/\///')
curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records/${dns_record_id}" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"type": "CNAME",
"name": "'"${domain}"'",
"content": "'"${deployment_url}"'",
"id": "'"${dns_record_id}"'",
"ttl": 1,
"proxied": true
}'
fi
fi
fi
done
rm public_suffix_list.dat
fi

0 comments on commit 1fba971

Please sign in to comment.