├── .github
├── README.template.md
├── actions
│ ├── eject
│ │ └── action.yml
│ ├── new-release
│ │ └── action.yml
│ ├── sync-assets
│ │ └── action.yml
│ └── trellis-cli
│ │ └── action.yml
├── dependabot.yml
├── examples
│ ├── dryrun-production.yml
│ ├── dryrun-staging.yml
│ ├── eject-production.yml
│ └── sage10-build-test.yml
├── template.yml
└── workflows
│ ├── deploy-production.yml
│ ├── deploy-staging.yml
│ ├── set-trellis-deploy-keys.yml
│ ├── sync-content-production-to-staging.yml
│ └── update-readme.yml
├── CODE_OF_CONDUCT.md
├── FUNDING.yml
├── LICENSE.md
└── README.md
/.github/README.template.md:
--------------------------------------------------------------------------------
1 | # example.com
2 |
3 | This [Trellis](https://roots.io/trellis/)-based WordPress project uses GitHub Actions for continuous deployment.
4 |
5 | [](https://github.com/MWDelaney/example.com/actions/workflows/deploy-staging.yml) [](https://github.com/MWDelaney/example.com/actions/workflows/deploy-production.yml)
6 |
7 | ## Deployment
8 |
9 | Deployment occurs automatically from this GitHub repository using [GitHub Actions](https://github.com/features/actions).
10 |
11 | This project deploys to the `staging` and `production` environments when a `pull_request` is `merged` to `staging` or `main` branches respectively.
12 |
13 | GitHub **Deployments** maintain a history of deployments and provide links to the current deployments in each.
14 |
15 | [See the current deployments](https://github.com/MWDelaney/example.com/deployments)
16 |
17 |
18 | Initial Setup
19 |
20 | _Note: these instructions presume your `staging` and `production` environments (servers) and DNS are already configured._
21 |
22 | ### System Requirements
23 |
24 | * [Trellis CLI](https://github.com/roots/trellis-cli)
25 | * [Github CLI](https://cli.github.com)
26 |
27 | ### 1. Create GitHub Secrets
28 |
29 | Deployment relies on 4 GitHub secrets:
30 |
31 | Modify and run the following to generate these secrets:
32 |
33 | ```bash
34 | trellis key generate && gh secret set ANSIBLE_VAULT_PASSWORD -b $(cat trellis/.vault_pass) && gh secret set TRELLIS_SITE_SLUG -b example.com
35 | ```
36 |
37 | #### Secrets
38 |
39 | * `TRELLIS_DEPLOY_SSH_PRIVATE_KEY` - A private key used by GitHub to connect to your environments.
40 | * `TRELLIS_DEPLOY_SSH_KNOWN_HOSTS` - `known_hosts` keys for your environments.
41 | * `ANSIBLE_VAULT_PASSWORD` - Your new Trellis project's [vault password](https://roots.io/trellis/docs/vault/).
42 | * `TRELLIS_SITE_SLUG` - The slug from your new Trellis project's `wordpress_sites.yml` file.
43 |
44 | ### 2. Generate Trellis aliases
45 |
46 | From your `site` directory, run:
47 |
48 | ```bash
49 | trellis alias
50 | ```
51 |
52 | And update `site/wp-cli.yml` as instructed.
53 |
54 | ### 3. Grant workflow permissions
55 |
56 | 1. In this repository, navigate to `Settings` -> `Actions` -> `General` -> `Workflow Permissions`.
57 | 2. Enable "read and write" permissions.
58 |
59 | ### 4. Reprovision your environments to allow GitHub's deploy key
60 |
61 | Run the following:
62 |
63 | ```bash
64 | trellis provision staging && trellis provision production
65 | ```
66 |
67 |
68 |
69 | ## Development
70 |
71 | 1) Clone this repository locally
72 | 2) In the repository directry, run `trellis init`
73 | 3) In the repository directory, run `trellis up`
74 |
--------------------------------------------------------------------------------
/.github/actions/eject/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Eject site for delivery'
2 | description: 'Eject Trellis site for delivery to traditional WordPress environments'
3 |
4 | inputs:
5 | from:
6 | description: 'The environment to sync from'
7 | required: true
8 |
9 | trellis_deploy_ssh_private_key:
10 | description: 'The SSH private key to use for deployment'
11 | required: true
12 |
13 | trellis_deploy_ssh_known_hosts:
14 | description: 'The SSH known hosts to use for deployment'
15 | required: true
16 |
17 | trellis_site_slug:
18 | description: 'The Trellis site slug'
19 | required: true
20 |
21 | github_token:
22 | description: 'The GitHub token to use'
23 | required: true
24 |
25 | working_directory:
26 | description: 'The working directory to use'
27 | required: true
28 |
29 | runs:
30 | using: 'composite'
31 | steps:
32 |
33 | # Get the current date and time in both human-readable and machine-readable formats
34 | - name: Get the date and time
35 | shell: bash
36 | id: get_date
37 | run: |
38 | echo "human_date=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_OUTPUT
39 | echo "machine_date=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
40 |
41 | # Set up known hosts
42 | - uses: shimataro/ssh-key-action@v2
43 | with:
44 | key: ${{ inputs.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
45 | known_hosts: ${{ inputs.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
46 |
47 | # Set up SSH agent
48 | - uses: webfactory/ssh-agent@v0.8.0
49 | with:
50 | ssh-private-key: ${{ inputs.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
51 |
52 | # Install WP-CLI
53 | - name: Setup WP-CLI
54 | uses: godaddy-wordpress/setup-wp-cli@1
55 |
56 | # Use WP CLI to the "FROM" site info
57 | - name: Get "from" site info
58 | shell: bash
59 | id: from_site
60 | working-directory: ${{ inputs.working_directory }}
61 | run: |
62 | echo "url=$(wp @"${{ inputs.from }}" option get home)" >> $GITHUB_OUTPUT
63 | echo "domain=$(wp @${{ inputs.from }} option get home | sed 's/https\?:\/\///')" >> $GITHUB_OUTPUT
64 | echo "dir=/srv/www/${{ inputs.TRELLIS_SITE_SLUG }}/current/web/app" >> $GITHUB_OUTPUT
65 | echo "ssh_user=web" >> $GITHUB_OUTPUT
66 |
67 | # If this is the production environment, export the database using wp-cli and pipe it to a local file.
68 | - name: 🗃️ Export database
69 | shell: bash
70 | working-directory: ${{ inputs.working_directory }}
71 | run: |
72 | wp @"${{ inputs.from }}" search-replace app/uploads wp-content/uploads --export > ./"${{ inputs.from }}-${{ steps.get_date.outputs.machine_date }}".sql
73 |
74 | # Check that the database export file exists
75 | - uses: andstor/file-existence-action@v2
76 | if: ${{ inputs.environment == 'production' }}
77 | id: check_db_file
78 | with:
79 | files: "site/${{ inputs.environment }}-*.sql"
80 | fail: true
81 |
82 | # Download the app directory from the production environment using rsync
83 | - name: 📥 Download production wp-content directory
84 | shell: bash
85 | working-directory: ${{ inputs.working_directory }}
86 | run: |
87 | rsync -Laz --progress --delete -e "ssh -o StrictHostKeyChecking=no" "${{ steps.from_site.outputs.ssh_user }}"@"${{ steps.from_site.outputs.domain }}":"${{ steps.from_site.outputs.dir }}"/ ./wp-content
88 |
89 | # Zip the wp-content directory
90 | - name: 🗜️ Compress wp-content directory
91 | shell: bash
92 | working-directory: ${{ inputs.working_directory }}
93 | run: |
94 | zip -r wp-content.zip wp-content
95 |
96 | # Create a Git tag with the environment name and machine-readable date
97 | - name: 🏷️ Tag version
98 | id: tag_version
99 | uses: mathieudutour/github-tag-action@v6.1
100 | with:
101 | github_token: ${{ inputs.github_token }}
102 | custom_tag: "${{ inputs.from }}-${{ steps.get_date.outputs.machine_date }}-eject"
103 | tag_prefix: ''
104 |
105 | # If this is the production environment, create a release with the database export as an asset
106 | - name: 📦 Create release
107 | uses: ncipollo/release-action@v1
108 | with:
109 | tag: "${{ steps.tag_version.outputs.new_tag }}"
110 | artifacts: "site/*.sql,site/wp-content.zip"
111 | token: ${{ inputs.github_token }}
112 | makeLatest: true
113 | name: "${{ inputs.trellis_site_slug }} - ${{ steps.get_date.outputs.human_date }} eject"
114 | body: |
115 | # ${{ inputs.from }} eject
116 |
117 | An export of the site's database and wp-content directory from the ${{ inputs.from }} environment.
118 |
119 | * 📅 ${{ steps.get_date.outputs.human_date }}
120 |
--------------------------------------------------------------------------------
/.github/actions/new-release/action.yml:
--------------------------------------------------------------------------------
1 | name: 'New Release'
2 | description: 'Publish a new release to GitHub'
3 |
4 | inputs:
5 | environment:
6 | description: 'The environment to deploy to'
7 | required: true
8 |
9 | site_url:
10 | description: 'The URL of the site to deploy'
11 | required: true
12 |
13 | ref:
14 | description: 'The Git ref to deploy'
15 | required: true
16 |
17 | github_token:
18 | description: 'The GitHub token to use'
19 | required: true
20 |
21 | trellis_site_slug:
22 | description: 'The Trellis site slug'
23 | required: true
24 |
25 | runs:
26 | using: 'composite'
27 | steps:
28 |
29 | # Get the current date and time in both human-readable and machine-readable formats
30 | - name: Get the date and time
31 | shell: bash
32 | id: get_date
33 | run: |
34 | echo "human_date=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_OUTPUT
35 | echo "machine_date=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
36 |
37 | # Use WP CLI to the site info
38 | - name: Get ${{ inputs.environment }} site info
39 | shell: bash
40 | id: from_site
41 | working-directory: site
42 | run: |
43 | echo "url=$(wp @"${{ inputs.environment }}" option get home)" >> $GITHUB_OUTPUT
44 | echo "domain=$(trellis exec ansible-inventory --list | jq -r '.["${{ inputs.environment }}"].hosts[0]')" >> $GITHUB_OUTPUT
45 | echo "dir=/srv/www/${{ inputs.TRELLIS_SITE_SLUG }}/current/web/app/uploads" >> $GITHUB_OUTPUT
46 | echo "ssh_user=web" >> $GITHUB_OUTPUT
47 |
48 | # Create a Git tag with the environment name and machine-readable date
49 | - name: 🏷️ Tag version
50 | id: tag_version
51 | uses: mathieudutour/github-tag-action@v6.1
52 | with:
53 | github_token: ${{ inputs.github_token }}
54 | custom_tag: "${{ inputs.environment }}-${{ steps.get_date.outputs.machine_date }}"
55 | tag_prefix: ''
56 |
57 | # If this is the production environment, export the database to a local file with the name of the environment and the date
58 | - name: 🗃️ Export database
59 | shell: bash
60 | if: ${{ inputs.environment == 'production' }}
61 | working-directory: site
62 | run: |
63 | wp @"${{ inputs.environment }}" db export --default-character-set=utf8mb4 - > ./"${{ inputs.environment }}"-"$(date +'%Y-%m-%d-%H-%M-%S')".sql
64 |
65 | # Download the app/uploads directory from the production environment using rsync
66 | - name: 📥 Download production uploads directory
67 | shell: bash
68 | if: ${{ inputs.environment == 'production' }}
69 | run: |
70 | rsync -Laz --progress --delete -e "ssh -o StrictHostKeyChecking=no" "${{ steps.from_site.outputs.ssh_user }}"@"${{ steps.from_site.outputs.domain }}":"${{ steps.from_site.outputs.dir }}"/ ./uploads
71 |
72 | # Zip the uploads directory
73 | - name: 🗜️ Compress uploads directory
74 | shell: bash
75 | if: ${{ inputs.environment == 'production' }}
76 | run: |
77 | zip -r uploads-"${{ steps.get_date.outputs.machine_date }}".zip ./uploads
78 |
79 | # If this is the production environment, create a release with the database export as an asset
80 | - name: 📦 Create release
81 | if: ${{ inputs.environment == 'production' }}
82 | uses: ncipollo/release-action@v1
83 | with:
84 | tag: "${{ steps.tag_version.outputs.new_tag }}"
85 | artifacts: "site/*.sql,uploads-*.zip"
86 | token: ${{ inputs.github_token }}
87 | makeLatest: true
88 | name: "${{ inputs.trellis_site_slug }} - ${{ steps.get_date.outputs.human_date }}"
89 | body: |
90 | # ${{ inputs.environment }}
91 |
92 | * 🔗 ${{ inputs.site_url }}
93 | * 📅 ${{ steps.get_date.outputs.human_date }}
94 |
95 | ${{ steps.tag_version.outputs.changelog }}
96 |
--------------------------------------------------------------------------------
/.github/actions/sync-assets/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Sync assets'
2 | description: 'Synchronize assets between environments'
3 |
4 | inputs:
5 | from:
6 | description: 'The environment to sync from'
7 | required: true
8 |
9 | to:
10 | description: 'The environment to sync to'
11 | required: true
12 |
13 | trellis_deploy_ssh_private_key:
14 | description: 'The SSH private key to use for deployment'
15 | required: true
16 |
17 | trellis_deploy_ssh_known_hosts:
18 | description: 'The SSH known hosts to use for deployment'
19 | required: true
20 |
21 | trellis_site_slug:
22 | description: 'The Trellis site slug'
23 | required: true
24 |
25 | working_directory:
26 | description: 'The working directory to use'
27 | required: true
28 |
29 | github_token:
30 | description: 'The GitHub token to use'
31 | required: true
32 |
33 | ansible_vault_password:
34 | description: 'The Ansible vault password to use'
35 | required: true
36 |
37 | runs:
38 | using: 'composite'
39 | steps:
40 |
41 | # Set up known hosts
42 | - uses: shimataro/ssh-key-action@v2
43 | with:
44 | key: ${{ inputs.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
45 | known_hosts: ${{ inputs.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
46 |
47 | # Set up SSH agent
48 | - uses: webfactory/ssh-agent@v0.8.0
49 | with:
50 | ssh-private-key: ${{ inputs.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
51 |
52 | # Install Trellis CLI
53 | - uses: roots/setup-trellis-cli@v1
54 | with:
55 | repo-token: ${{ inputs.GITHUB_TOKEN }}
56 | ansible-vault-password: ${{ inputs.ANSIBLE_VAULT_PASSWORD }}
57 |
58 |
59 | # Install WP-CLI
60 | - name: Setup WP-CLI
61 | uses: godaddy-wordpress/setup-wp-cli@1
62 |
63 | # Use WP CLI to the "FROM" site info
64 | - name: Get "from" site info
65 | shell: bash
66 | id: from_site
67 | working-directory: ${{ inputs.WORKING_DIRECTORY }}
68 | run: |
69 | echo "url=$(wp @"${{ inputs.FROM }}" option get home)" >> $GITHUB_OUTPUT
70 | echo "domain=$(trellis exec ansible-inventory --list | jq -r '.["${{ inputs.FROM }}"].hosts[0]')" >> $GITHUB_OUTPUT
71 | echo "dir=/srv/www/${{ inputs.TRELLIS_SITE_SLUG }}/shared/uploads" >> $GITHUB_OUTPUT
72 | echo "ssh_user=web" >> $GITHUB_OUTPUT
73 |
74 | # Use WP CLI to get the "TO" site info
75 | - name: Get "to" site info
76 | shell: bash
77 | id: to_site
78 | working-directory: ${{ inputs.WORKING_DIRECTORY }}
79 | run: |
80 | echo "url=$(wp @"${{ inputs.TO }}" option get home)" >> $GITHUB_OUTPUT
81 | echo "domain=$(trellis exec ansible-inventory --list | jq -r '.["${{ inputs.TO }}"].hosts[0]')" >> $GITHUB_OUTPUT
82 | echo "dir=/srv/www/${{ inputs.TRELLIS_SITE_SLUG }}/shared/uploads" >> $GITHUB_OUTPUT
83 | echo "ssh_user=web" >> $GITHUB_OUTPUT
84 |
85 | # Sync database with WP-CLI
86 | - name: 🗃️ Sync database
87 | working-directory: ${{ inputs.WORKING_DIRECTORY }}
88 | shell: bash
89 | run: |
90 | wp "@${{ inputs.TO }}" db export --default-character-set=utf8mb4 &&
91 | wp "@${{ inputs.TO }}" db reset --yes &&
92 | wp "@${{ inputs.FROM }}" db export --default-character-set=utf8mb4 - | wp "@${{ inputs.TO }}" db import - &&
93 | wp "@${{ inputs.TO }}" search-replace "${{ steps.from_site.outputs.url }}" "${{ steps.to_site.outputs.url }}" --all-tables-with-prefix
94 |
95 | # Sync uploads with ssh and rsync
96 | - name: 🍱 Sync uploads
97 | shell: bash
98 | run: |
99 | ssh -o ForwardAgent=yes ${{ steps.from_site.outputs.ssh_user }}@${{ steps.from_site.outputs.domain }} "rsync -aze 'ssh -o StrictHostKeyChecking=no' --progress ${{ steps.from_site.outputs.dir }} ${{ steps.to_site.outputs.ssh_user }}@${{ steps.to_site.outputs.domain }}:${{ steps.to_site.outputs.dir }}"
100 |
101 | # Report success to the log
102 | - name: 🎉 Sync complete
103 | shell: bash
104 | run: |
105 | echo "::notice::Successfully synchronized assets from ${{ inputs.from }} to ${{ inputs.to }}"
106 |
--------------------------------------------------------------------------------
/.github/actions/trellis-cli/action.yml:
--------------------------------------------------------------------------------
1 | name: '🚀 Deploy to Trellis environment'
2 | description: 'Deploys to a Trellis environment using trellis-cli'
3 |
4 | inputs:
5 | extra-vars:
6 | description: 'Extra variables to pass to Ansible'
7 | required: true
8 | default: '""'
9 |
10 | environment:
11 | description: 'The environment to deploy to'
12 | required: true
13 |
14 | github_token:
15 | description: 'The GitHub token to use'
16 | required: true
17 |
18 | trellis_site_slug:
19 | description: 'The Trellis site slug'
20 | required: true
21 |
22 | trellis_deploy_ssh_private_key:
23 | description: 'The SSH private key to use for deployment'
24 | required: true
25 |
26 | trellis_deploy_ssh_known_hosts:
27 | description: 'The SSH known hosts to use for deployment'
28 | required: true
29 |
30 | ansible_vault_password:
31 | description: 'The Ansible vault password to use'
32 | required: true
33 |
34 | dry_run:
35 | description: 'Whether to run a dry-run deployment'
36 | required: false
37 |
38 | runs:
39 | using: 'composite'
40 | steps:
41 |
42 | # If this is a dry run, show a message indicating so
43 | - name: Is this a dry run?
44 | if: ${{ inputs.dry_run }}
45 | shell: bash
46 | run: |
47 | echo "::notice::This is a dry run, this deployment will not be finalized."
48 |
49 | # Start a GitHub "deployment"
50 | - name: Start deployment
51 | uses: bobheadxi/deployments@v1
52 | id: deployment
53 | if: ${{ inputs.dry_run == '' }}
54 | with:
55 | step: start
56 | token: ${{ inputs.GITHUB_TOKEN }}
57 | env: ${{ inputs.environment }}
58 |
59 | # Optional sage build, should be refactored into separate workflow
60 | - uses: actions/setup-node@v3
61 | with:
62 | node-version: '16'
63 |
64 | # Check that the deploy.yml file exists, a reasonable check that this is a Trellis project
65 | - uses: andstor/file-existence-action@v2
66 | id: check_files
67 | with:
68 | files: "trellis/deploy.yml"
69 |
70 | # Set up known hosts
71 | - uses: shimataro/ssh-key-action@v2
72 | with:
73 | key: ${{ inputs.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
74 | known_hosts: ${{ inputs.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
75 |
76 | # Set up SSH agent
77 | - uses: webfactory/ssh-agent@v0.8.0
78 | with:
79 | ssh-private-key: ${{ inputs.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
80 |
81 | # Install Trellis CLI
82 | - uses: roots/setup-trellis-cli@v1
83 | with:
84 | repo-token: ${{ inputs.GITHUB_TOKEN }}
85 | ansible-vault-password: ${{ inputs.ANSIBLE_VAULT_PASSWORD }}
86 |
87 | # Run Trellis deploy
88 | - name: Deploy
89 | shell: bash
90 | if: steps.check_files.outputs.files_exists == 'true'
91 | run: trellis deploy --extra-vars ${{ inputs.extra-vars }} ${{ inputs.environment }}
92 |
93 | # install WP-CLI
94 | - name: Setup WP-CLI
95 | if: ${{ inputs.dry_run == '' }}
96 | uses: godaddy-wordpress/setup-wp-cli@1
97 |
98 | # Use WP CLI to get the site URL from the deployed site
99 | - name: Get site URL
100 | if: ${{ inputs.dry_run == '' }}
101 | shell: bash
102 | working-directory: site
103 | id: site_url
104 | run: |
105 | echo "url=$(wp @"${{ inputs.environment }}" option get home)" >> $GITHUB_OUTPUT
106 |
107 | # Call the new-release action to create a tag and/or release
108 | - name: Create release
109 | uses: ./.github/actions/new-release
110 | if: ${{ inputs.dry_run == '' }}
111 | with:
112 | environment: ${{ inputs.environment }}
113 | site_url: ${{ steps.site_url.outputs.url }}
114 | ref: ${{ github.event.pull_request.base.ref }}
115 | github_token: ${{ inputs.GITHUB_TOKEN }}
116 | trellis_site_slug: ${{ inputs.TRELLIS_SITE_SLUG }}
117 |
118 | # Finish the GitHub "deployment"
119 | - name: Finalize deployment status
120 | uses: bobheadxi/deployments@v1
121 | if: ${{ inputs.dry_run == '' }}
122 | with:
123 | step: finish
124 | token: ${{ inputs.GITHUB_TOKEN }}
125 | status: ${{ job.status }}
126 | env: ${{ steps.deployment.outputs.env }}
127 | env_url: ${{ steps.site_url.outputs.url }}
128 | deployment_id: ${{ steps.deployment.outputs.deployment_id }}
129 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # ./github/dependabot.yml
2 | ##
3 | # Dependabot configuration for Bedrock
4 | #
5 | # Check for updates to Composer packages weekly
6 | ##
7 |
8 | version: 2
9 | updates:
10 | - package-ecosystem: "composer" # See documentation for possible values
11 | directory: "/site" # Location of package manifests
12 | target-branch: "staging"
13 | schedule:
14 | interval: "weekly"
15 | open-pull-requests-limit: 20
16 |
--------------------------------------------------------------------------------
/.github/examples/dryrun-production.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/dryrun-production.yml
2 | ##
3 | # Dry-run deploy to a temporary directory in the production environment with Trellis
4 | ##
5 |
6 | name: 🧪 Dry-run to production
7 | run-name: dry-run-production
8 |
9 | on:
10 | workflow_dispatch:
11 | pull_request:
12 | branches: [main]
13 |
14 | env:
15 | environment: production
16 | script: |
17 | ---
18 | - name: "This is a dry-run, delete the deploy."
19 | ansible.builtin.file:
20 | state: absent
21 | path: "{{ deploy_helper.new_release_path }}"
22 |
23 | - name: "This is a dry-run, stop here."
24 | meta: end_play
25 | extra-vars: |
26 | {
27 | "deploy_build_after": [
28 | "{{ playbook_dir }}/roles/deploy/hooks/build-after.yml",
29 | "{{ playbook_dir }}/deploy-hooks/build-after.yml",
30 | "/build-after.yml"
31 | ],
32 | "dry_run": true,
33 | "project_root": "/tmp/trellis"
34 | }
35 |
36 | jobs:
37 | dryrun-production:
38 | runs-on: ubuntu-latest
39 | steps:
40 |
41 | # Checkout the repo
42 | - uses: actions/checkout@v3
43 | with:
44 | ref: ${{ github.event.pull_request.base.ref }}
45 |
46 | # Create a file with the contents of the script environment variable
47 | - name: Create script file
48 | run: echo "${{ env.script }}" > build-after.yml
49 |
50 | # Create a yml file with the contents of the extra-vars
51 | - name: Create extra-vars file
52 | run: |
53 | echo "${{ env.extra-vars }}" > extra-vars.json
54 |
55 | # Deploy site to production
56 | - uses: ./.github/actions/trellis-cli
57 | name: Dry-run deploy to production
58 | if: github.event.pull_request.merged || github.event_name == 'workflow_dispatch' || github.repository != 'MWDelaney/trellis-template'
59 | with:
60 | extra-vars: '"@file:/extra-vars.json"'
61 | environment: ${{ env.environment }}
62 | github_token: ${{ secrets.GITHUB_TOKEN }}
63 | trellis_site_slug: ${{ secrets.TRELLIS_SITE_SLUG }}
64 | trellis_deploy_ssh_private_key: ${{ secrets.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
65 | trellis_deploy_ssh_known_hosts: ${{ secrets.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
66 | ansible_vault_password: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
67 | dry_run: true
68 |
--------------------------------------------------------------------------------
/.github/examples/dryrun-staging.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/dryrun-staging.yml
2 | ##
3 | # Dry-run deploy to a temporary directory in the staging environment with Trellis
4 | ##
5 |
6 | name: 🧪 Dry-run to staging
7 | run-name: dry-run-staging
8 |
9 | on:
10 | workflow_dispatch:
11 | pull_request:
12 | branches: [staging]
13 |
14 | env:
15 | environment: staging
16 | script: |
17 | ---
18 | - name: "This is a dry-run, delete the deploy."
19 | ansible.builtin.file:
20 | state: absent
21 | path: "{{ deploy_helper.new_release_path }}"
22 |
23 | - name: "This is a dry-run, stop here."
24 | meta: end_play
25 | extra-vars: |
26 | {
27 | "deploy_build_after": [
28 | "{{ playbook_dir }}/roles/deploy/hooks/build-after.yml",
29 | "{{ playbook_dir }}/deploy-hooks/build-after.yml",
30 | "/build-after.yml"
31 | ],
32 | "dry_run": true,
33 | "project_root": "/tmp/trellis"
34 | }
35 |
36 | jobs:
37 | dryrun-staging:
38 | runs-on: ubuntu-latest
39 | steps:
40 |
41 | # Checkout the repo
42 | - uses: actions/checkout@v3
43 | with:
44 | ref: ${{ github.event.pull_request.base.ref }}
45 |
46 | # Create a file with the contents of the script environment variable
47 | - name: Create script file
48 | run: echo "${{ env.script }}" > build-after.yml
49 |
50 | # Create a yml file with the contents of the extra-vars
51 | - name: Create extra-vars file
52 | run: |
53 | echo "${{ env.extra-vars }}" > extra-vars.json
54 |
55 | # Deploy site to staging
56 | - uses: ./.github/actions/trellis-cli
57 | name: Dry-run deploy to staging
58 | if: github.event.pull_request.merged || github.event_name == 'workflow_dispatch' || github.repository != 'MWDelaney/trellis-template'
59 | with:
60 | extra-vars: '"@file:/extra-vars.json"'
61 | environment: ${{ env.environment }}
62 | github_token: ${{ secrets.GITHUB_TOKEN }}
63 | trellis_site_slug: ${{ secrets.TRELLIS_SITE_SLUG }}
64 | trellis_deploy_ssh_private_key: ${{ secrets.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
65 | trellis_deploy_ssh_known_hosts: ${{ secrets.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
66 | ansible_vault_password: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
67 | dry_run: true
68 |
--------------------------------------------------------------------------------
/.github/examples/eject-production.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/eject-production.yml
2 | ##
3 | # Eject production
4 | #
5 | # Export a Trellis-managed site from production
6 | # for delivery to a traditional WordPress environment
7 | # and attach artifacts to the workflow run for download
8 | ##
9 |
10 | name: ⏏️ Eject production for delivery
11 | run-name: eject-production
12 |
13 | on:
14 | workflow_dispatch:
15 |
16 | env:
17 | from: production
18 |
19 | jobs:
20 | eject-production:
21 | runs-on: ubuntu-latest
22 | steps:
23 |
24 | # Checkout the repo
25 | - uses: actions/checkout@v3
26 | with:
27 | ref: ${{ github.event.pull_request.base.ref }}
28 |
29 | # Eject production for delivery
30 | - uses: ./.github/actions/eject
31 | name: Eject production for delivery
32 | with:
33 | from: ${{ env.from }}
34 | trellis_site_slug: ${{ secrets.TRELLIS_SITE_SLUG }}
35 | trellis_deploy_ssh_private_key: ${{ secrets.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
36 | trellis_deploy_ssh_known_hosts: ${{ secrets.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
37 | working_directory: ./site
38 | github_token: ${{ secrets.GITHUB_TOKEN }}
39 |
--------------------------------------------------------------------------------
/.github/examples/sage10-build-test.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/sage10-build.yml
2 | ##
3 | # Build a Sage 10-based theme
4 | #
5 | # ⚠️ This example assumes your theme is using Sage 10
6 | #
7 | # Replace `sage` below with your theme folder
8 | #
9 | ##
10 |
11 | name: 🚧 Sage 10 build test
12 |
13 | on: [push]
14 |
15 | env:
16 | theme_slug: sage # Update this with your theme's directory name
17 | node_version: '16'
18 |
19 | jobs:
20 | yarn-build:
21 |
22 | runs-on: ubuntu-latest
23 | defaults:
24 | run:
25 | working-directory: ./site/web/app/themes/${{ env.theme_slug }}
26 | steps:
27 | - uses: actions/checkout@v3
28 | - name: Use Node.js ${{ env.node_version }}
29 | uses: actions/setup-node@v3
30 | with:
31 | node-version: ${{ env.node_version }}
32 | cache: yarn
33 | cache-dependency-path: ./site/web/app/themes/${{ env.theme_slug }}/yarn.lock
34 |
35 | - run: composer install
36 | - run: yarn install
37 | - run: yarn build
38 |
--------------------------------------------------------------------------------
/.github/template.yml:
--------------------------------------------------------------------------------
1 | author:mwdelaney
2 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-production.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/deploy-production.yml
2 | ##
3 | # Deploy to production with Trellis
4 | ##
5 |
6 | name: 🚀 Deploy to production
7 | run-name: deploy-production
8 |
9 | on:
10 | workflow_dispatch:
11 | pull_request:
12 | types: [closed]
13 | branches: [main]
14 |
15 | env:
16 | environment: production
17 |
18 | jobs:
19 | deploy-production:
20 | runs-on: ubuntu-latest
21 | if: ${{ github.actor != 'dependabot[bot]' }}
22 | steps:
23 |
24 | # Checkout the repo
25 | - uses: actions/checkout@v3
26 | with:
27 | ref: ${{ github.event.pull_request.base.ref }}
28 |
29 | # Deploy site to production
30 | - uses: ./.github/actions/trellis-cli
31 | name: Deploy to production
32 | if: github.event.pull_request.merged || github.event_name == 'workflow_dispatch' || github.repository != 'MWDelaney/trellis-template'
33 | with:
34 | extra-vars: '""'
35 | environment: ${{ env.environment }}
36 | github_token: ${{ secrets.GITHUB_TOKEN }}
37 | trellis_site_slug: ${{ secrets.TRELLIS_SITE_SLUG }}
38 | trellis_deploy_ssh_private_key: ${{ secrets.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
39 | trellis_deploy_ssh_known_hosts: ${{ secrets.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
40 | ansible_vault_password: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
41 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-staging.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/deploy-staging.yml
2 | ##
3 | # Deploy to staging with Trellis
4 | ##
5 |
6 | name: 🚀 Deploy to staging
7 | run-name: deploy-staging
8 |
9 | on:
10 | workflow_dispatch:
11 | pull_request:
12 | types: [closed]
13 | branches: [staging]
14 |
15 | env:
16 | environment: staging
17 |
18 | jobs:
19 | deploy-staging:
20 | if: ${{ github.actor != 'dependabot[bot]' }}
21 | runs-on: ubuntu-latest
22 | steps:
23 |
24 | # Checkout the repo
25 | - uses: actions/checkout@v3
26 | with:
27 | ref: ${{ github.event.pull_request.base.ref }}
28 |
29 | # Deploy site to staging
30 | - uses: ./.github/actions/trellis-cli
31 | name: Deploy to staging
32 | if: github.event.pull_request.merged || github.event_name == 'workflow_dispatch' || github.repository != 'MWDelaney/trellis-template'
33 | with:
34 | extra-vars: '""'
35 | environment: ${{ env.environment }}
36 | github_token: ${{ secrets.GITHUB_TOKEN }}
37 | trellis_site_slug: ${{ secrets.TRELLIS_SITE_SLUG }}
38 | trellis_deploy_ssh_private_key: ${{ secrets.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
39 | trellis_deploy_ssh_known_hosts: ${{ secrets.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
40 | ansible_vault_password: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
41 |
--------------------------------------------------------------------------------
/.github/workflows/set-trellis-deploy-keys.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/reset-trellis-deploy-keys.yml
2 | ##
3 | # Set or reset SSH deploy keys for a Trellis environment
4 | #
5 | # Set or reset the SSH keys in a Trellis environment to the
6 | # GitHub public key stored in the Trellis project at `trellis/public_keys`
7 | # and optionally add the public keys stored in GitHub secrets at `TRELLIS_DEPLOY_KEYS`
8 | # and the deploy keys configured in Trellis at `trellis/group_vars/all/users.yml`.
9 | ##
10 |
11 | name: 🔑 Set Trellis deploy keys
12 |
13 | on:
14 | workflow_dispatch:
15 | inputs:
16 | environment:
17 | description: 'Enter the Trellis environment to reset and choose at least one source of deploy keys to add'
18 | required: true
19 | default: 'production'
20 |
21 | from_trellis:
22 | type: boolean
23 | description: 'trellis/group_vars/all/users.yml'
24 | default: true
25 |
26 | from_secrets:
27 | type: boolean
28 | description: 'GitHub secret named TRELLIS_DEPLOY_KEYS'
29 | default: false
30 |
31 | new_key:
32 | description: 'Enter a new key'
33 |
34 | jobs:
35 | reset-trellis-deploy-keys:
36 | runs-on: ubuntu-latest
37 | steps:
38 |
39 | # Checkout the repo
40 | - uses: actions/checkout@v3
41 | with:
42 | ref: ${{ github.ref }}
43 |
44 | # Install WP-CLI
45 | - name: Setup WP-CLI
46 | uses: godaddy-wordpress/setup-wp-cli@1
47 |
48 | # Set up known hosts
49 | - uses: shimataro/ssh-key-action@v2
50 | with:
51 | key: ${{ secrets.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
52 | known_hosts: ${{ secrets.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
53 |
54 | # Set up SSH agent
55 | - uses: webfactory/ssh-agent@v0.8.0
56 | with:
57 | ssh-private-key: ${{ secrets.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
58 |
59 | # Use WP CLI to get information from the specified environment
60 | - name: Get site info
61 | shell: bash
62 | id: environment_site
63 | working-directory: site
64 | run: |
65 | echo "url=$(wp @"${{ inputs.environment }}" option get home)" >> $GITHUB_OUTPUT
66 | echo "domain=$(wp @${{ inputs.environment }} option get home | sed 's/https\?:\/\///')" >> $GITHUB_OUTPUT
67 | echo "dir=/srv/www/${{ secrets.TRELLIS_SITE_SLUG }}/shared/uploads" >> $GITHUB_OUTPUT
68 | echo "ssh_user=web" >> $GITHUB_OUTPUT
69 |
70 | # Get the contents of the ssh keys in the Trellis project at `trellis/public_keys`
71 | - name: Always get GitHub deploy keys from Trellis
72 | id: trellis_deploy_keys
73 | run: |
74 | echo "keys=$(cat trellis/public_keys/*.pub)" >> $GITHUB_OUTPUT
75 |
76 | # Get Trellis configured entries in `trellis/group_vars/all/users.yml`
77 | - name: Maybe get Trellis config keys
78 | uses: mikefarah/yq@v4
79 | id: trellis_config_keys
80 | if: ${{ inputs.from_trellis == true }}
81 | with:
82 | cmd: yq e '.users[] | select(.name == "{{ web_user }}") | .keys[]' trellis/group_vars/all/users.yml | grep -E '^https?://' | xargs -I {} curl -s {}
83 |
84 |
85 | # Get the contents of the ssh keys in the GitHub secrets
86 | - name: Maybe get GitHub secrets keys
87 | id: github_secrets_keys
88 | if: ${{ inputs.from_secrets == true }}
89 | run: |
90 | echo "keys=${{ secrets.TRELLIS_DEPLOY_KEYS }}" >> $GITHUB_OUTPUT
91 |
92 | # If the user has entered a new key, add it to the list of keys
93 | - name: Maybe add new key
94 | id: new_key
95 | if: ${{ inputs.new_key != '' }}
96 | run: |
97 | echo "keys=${{ inputs.new_key }}" >> $GITHUB_OUTPUT
98 |
99 | # Connect to the specififed environment via ssh set the contents of `~/.ssh/authorized_keys`
100 | - name: Replace all authorized keys
101 | shell: bash
102 | run: |
103 | ssh -o ForwardAgent=yes ${{ steps.environment_site.outputs.ssh_user }}@${{ steps.environment_site.outputs.domain }} "echo ${{ steps.trellis_deploy_keys.outputs.keys }}$'\n'${{ steps.trellis_config_keys.outputs.result }}$'\n'${{ steps.github_secrets_keys.outputs.keys }}${{ steps.new_key.outputs.keys }} > ~/.ssh/authorized_keys"
104 |
--------------------------------------------------------------------------------
/.github/workflows/sync-content-production-to-staging.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/sync-content-production-to-staging.yml
2 | ##
3 | # Sync content production->staging
4 | ##
5 |
6 | name: 🔄 Sync content production->staging
7 | run-name: sync-content-production-to-staging
8 |
9 | on:
10 | workflow_dispatch:
11 |
12 | env:
13 | from: production
14 | to: staging
15 |
16 | jobs:
17 | sync-content-production-to-staging:
18 | runs-on: ubuntu-latest
19 | steps:
20 |
21 | # Checkout the repo
22 | - uses: actions/checkout@v3
23 | with:
24 | ref: ${{ github.event.pull_request.base.ref }}
25 |
26 | # Sync content from production to staging
27 | - uses: ./.github/actions/sync-assets
28 | name: Sync assets from production to staging
29 | if: github.event.pull_request.merged || github.event_name == 'workflow_dispatch' || github.repository != 'MWDelaney/trellis-template'
30 | with:
31 | from: ${{ env.from }}
32 | to: ${{ env.to }}
33 | trellis_site_slug: ${{ secrets.TRELLIS_SITE_SLUG }}
34 | trellis_deploy_ssh_private_key: ${{ secrets.TRELLIS_DEPLOY_SSH_PRIVATE_KEY }}
35 | trellis_deploy_ssh_known_hosts: ${{ secrets.TRELLIS_DEPLOY_SSH_KNOWN_HOSTS }}
36 | github_token: ${{ secrets.GITHUB_TOKEN }}
37 | ansible_vault_password: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
38 | working_directory: ./site
39 |
--------------------------------------------------------------------------------
/.github/workflows/update-readme.yml:
--------------------------------------------------------------------------------
1 | # .github/workflows/update-readme.yml
2 | ##
3 | # Update readme to reflect repository name
4 | ##
5 |
6 | name: 📝 Update README
7 | run-name: update-readme
8 |
9 | on:
10 | workflow_dispatch:
11 |
12 | jobs:
13 | update-readme:
14 | runs-on: ubuntu-latest
15 | steps:
16 |
17 | #Checkout the repo
18 | - uses: actions/checkout@v3
19 |
20 | # Replace repository slug
21 | - name: Replace repository slug
22 | uses: jacobtomlinson/gha-find-replace@v2
23 | with:
24 | find: "MWDelaney/example.com"
25 | replace: "${{ github.repository_owner }}/${{ github.event.repository.name }}"
26 | include: ".github/README.template.md"
27 | regex: false
28 |
29 | # Replace repository title
30 | - name: Replace repository title
31 | uses: jacobtomlinson/gha-find-replace@v3
32 | with:
33 | find: "# example.com"
34 | replace: "# ${{ github.event.repository.name }}"
35 | include: ".github/README.template.md"
36 | regex: false
37 |
38 | # Change the filename to .README
39 | - name: Rename README
40 | shell: bash
41 | run: mv .github/README.template.md .github/README.md
42 |
43 | # Commit changes
44 | - name: Commit changes
45 | uses: EndBug/add-and-commit@v9
46 | with:
47 | message: "Update README"
48 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | michael@michaeldelaney.me.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: MWDelaney
4 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Michael W. Delaney
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🚀 Trellis GitHub Deployment
2 |
3 | Automatically deploy your [Trellis](https://roots.io/trellis/)-based WordPress site to `staging` and `production` environments on merge to `staging` and `main` branches respectively, and keep plugins, themes, and WordPress core up to date with Dependabot.
4 |
5 | 🔥 Based on [setup-trellis-cli](https://github.com/roots/setup-trellis-cli). This set of GitHub actions and workflows extend the functionality of that package to more tightly integrate with GitHub's native features.
6 |
7 | ## Features
8 |
9 | - 🚀 **Automatic (or manual) deployment** to `staging` and `production` environments using [GitHub Actions](https://github.com/features/actions) when pull requests are merged to your `staging` and `main` branches respectively.
10 | - 🔄 **On-Demand one-way sync** database and assets from `production` to `staging`.
11 | - 🔗 **Maintains a history of [GitHub Deployments](https://docs.github.com/en/rest/reference/repos#create-a-deployment)** and provides links to the current deployments in each environment.
12 | - 🔑 **Re-set deployment keys on-demand** when you need to change who has access to `staging` or `production`.
13 | - 📦 **WordPress plugin, core, and theme updates** managed with [Dependabot](https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/about-dependabot-version-updates).
14 | - 📝 **Optionally generates README.md** with deployment status badges and setup instructions.
15 |
16 | ### Optional Additional Workflows
17 |
18 |
19 | Click to expand
20 |
21 | - 🌱 **Sage 10 build test** on pull request or on-demand (make sure your theme builds before you deploy it!).
22 | - 🧪 **Dry-run deployments** to `staging` and `production` environments on pull request or on-demand (confirm Trellis can deploy successfully without finalizing the deployment).
23 | - ⏏️ **Eject WordPress site** from Bedrock and Trellis and prepare database and assets for migration to traditional WordPress hosting.
24 |
25 |
26 |
27 | ---
28 |
29 | ## Requirements
30 |
31 | - A [Trellis](https://roots.io/trellis/docs/installing-trellis/)-based WordPress website.
32 | - Provisioned remote servers for `staging` and `production` environments.
33 |
34 | **NOTE**: This project presumes your Trellis-based website and its `staging` and `production` environments are provisioned and deploying successfully.
35 |
36 | ## Installation
37 |
38 | 1. Copy the `.github` directory from this repository to your Trellis-based WordPress site's repository.
39 | 2. Refer to the Initial Setup instructions in `.github/README.md` to configure your GitHub repository for deployment.
40 |
41 | ---
42 |
43 | ## Usage
44 |
45 | ### Default Workflows
46 |
47 | These workflows are included and enabled by default.
48 |
49 |
50 | 🚀 Deploy to production
51 |
52 | ```md
53 | .github/workflows/deploy-production.yml
54 | ```
55 |
56 | Automatically deploys to the `production` environment when a `pull_request` is `merged` to the `main` branch. This action can also be run manually from the "Actions" tab in GitHub.
57 |
58 | When a deploy to `production` is completed, the following occurs:
59 |
60 | - A new release is created with the current date and time including site's database and uploads attached as artifacts (GitHub release size restrictions apply).
61 | - A GitHub Deployment is created with a link to the environment.
62 |
63 |
64 |
65 |
66 | 🚀 Deploy to staging
67 |
68 | ```md
69 | .github/workflows/deploy-staging.yml
70 | ```
71 |
72 | Automatically deploys to the `staging` environment when a `pull_request` is `merged` to the `staging` branch. This action can also be run manually from the "Actions" tab in GitHub.
73 |
74 | When a deploy to `staging` is completed, the following occurs:
75 |
76 | - A new tag is created with the current date and time.
77 | - A GitHub Deployment is created with a link to the environment.
78 |
79 |
80 |
81 |
82 | 🔄 Sync content production->staging
83 |
84 | ```md
85 | .github/workflows/sync-content-production-to-staging.yml
86 | ```
87 |
88 | Copy the database and assets from the `production` environment to the `staging` environment overwriting the staging environment's database and assets.
89 |
90 |
91 |
92 |
93 | 🔑 Set Trellis deploy keys
94 |
95 | ```md
96 | .github/workflows/set-trellis-deploy-keys.yml
97 | ```
98 |
99 | Updates the ssh keys used by Trellis to deploy to the `staging` or `production` environments. This action can be run manually from the "Actions" tab in GitHub.
100 |
101 | This action replaces the current deploy keys with keys with keys defined in one or more of the following locations:
102 |
103 | - `trellis/group_vars/all/users.yml`
104 | - GitHub secrets named `TRELLIS_DEPLOY_KEYS`
105 | - A new key entered manually when running the action
106 |
107 |
108 |
109 | 📝 Update README
110 |
111 | ```md
112 | .github/workflows/update-readme.yml
113 | ```
114 |
115 | Updates the README.md with the current deployment status badges. This action can be run manually from the "Actions" tab in GitHub.
116 |
117 |
118 | ### Optional Workflows
119 |
120 | These example workflows are included to expand the functionality of this project. They are not enabled by default.
121 |
122 |
123 | 🧪 Dry-Run to Production
124 |
125 | ```md
126 | .github/examples/dryrun-production.yml
127 | ```
128 |
129 | ⚠️ **NOTE:** This workflow must be moved to the `.github/workflows` directory to be used.
130 |
131 | Performs a "dry-run" deployment to the `production` environment, testing all aspects of a Trellis deployment without finalizing the deploy. Automatically deploys to the `staging` environment when a `pull_request` is `opened` to the `main` branch. This action can also be run manually from the "Actions" tab in GitHub.
132 |
133 |
134 | 🧪 Dry-Run to Staging
135 |
136 | ```md
137 | .github/examples/dryrun-staging.yml
138 | ```
139 |
140 | ⚠️ **NOTE:** This workflow must be moved to the `.github/workflows` directory to be used.
141 |
142 | Performs a "dry-run" deployment to the `staging` environment, testing all aspects of a Trellis deployment without finalizing the deploy. Automatically deploys to the `staging` environment when a `pull_request` is `opened` to the `staging` branch. This action can also be run manually from the "Actions" tab in GitHub.
143 |
144 |
145 | 🌱 Sage 10 Build Test
146 |
147 | ```md
148 | .github/examples/sage10-build-test.yml
149 | ```
150 |
151 | ⚠️ **NOTE:** This workflow must be moved to the `.github/workflows` directory to be used.
152 |
153 | ⚠️ **NOTE:** You must edit this workflow to update the `theme_slug` variable with your theme's slug.
154 |
155 | Builds the Sage 10 theme and runs the theme's tests. Automatically runs when a `push` is made to any branch.
156 |
157 |
158 | ⏏️ Eject Production
159 |
160 | ```md
161 | .github/examples/eject-production.yml
162 | ```
163 |
164 | ⚠️ **NOTE:** This workflow must be moved to the `.github/workflows` directory to be used.
165 |
166 | Exports a WordPress site built with Trellis from the `production` environment for delivery to a traditional WordPress environment and attach artifacts to the workflow run for download. This action can be run manually from the "Actions" tab in GitHub.
167 |
168 |
169 | ### Dependabot
170 |
171 |
172 | 🤖 WordPress core, plugin, and theme updates
173 |
174 | Dependabot will check for updates to WordPress themes, plugins, and core as defined in `site/composer.json` on a weekly basis and propose updates as pull requests to the `staging` branch. You can change this behavior by editing the `.github/dependabot.yml` file.
175 |
176 |
--------------------------------------------------------------------------------