Skip to content

Added missing Polish translations #30489

Added missing Polish translations

Added missing Polish translations #30489

Workflow file for this run

name: CI
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
push:
# Ref: GHA Filter pattern syntax: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#filter-pattern-cheat-sheet
# Run on pushes to main, release branches, and previous/future major version branches
branches:
- main
- 'v[0-9]+.*' # Matches any release branch, e.g. v6.0.3, v12.1.0
- '[0-9]+.x' # Matches any major version branch, e.g. 5.x, 23.x
env:
FORCE_COLOR: 1
HEAD_COMMIT: ${{ github.sha }}
CACHED_DEPENDENCY_PATHS: |
${{ github.workspace }}/node_modules
${{ github.workspace }}/apps/*/node_modules
${{ github.workspace }}/ghost/*/node_modules
${{ github.workspace }}/e2e/node_modules
~/.cache/ms-playwright/
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
NODE_VERSION: 22.18.0
concurrency:
group: ${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
job_setup:
name: Setup
runs-on: ubuntu-latest
# Having certain parts of our huge CI workflow run on a specific label is an anti-pattern.
# Long term, we want to get away from this by having all of our tests run on every PR, and have the staging deploy either be automatic or a different workflow
# This logic skips the entire workflow if triggered by a label that doesn't contain "test" or "deploy" - there's nothing new to do in that case
if: |
github.event_name != 'pull_request' ||
(github.event.action == 'labeled' && (contains(github.event.label.name, 'test') || contains(github.event.label.name, 'deploy'))) ||
(github.event.action == 'unlabeled' && (contains(github.event.label.name, 'test') || contains(github.event.label.name, 'deploy'))) ||
(github.event.action != 'labeled' && github.event.action != 'unlabeled')
timeout-minutes: 15
env:
IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
IS_DEVELOPMENT: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/5.x' || github.ref == 'refs/heads/6.x' }}
IS_SIX: ${{ github.ref == 'refs/heads/6.x' }}
IS_SIX_PR: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref == '6.x' }}
permissions:
pull-requests: read
steps:
- name: Checkout current commit
uses: actions/checkout@v4
with:
ref: ${{ env.HEAD_COMMIT }}
fetch-depth: 2
- name: Output GitHub context
if: env.RUNNER_DEBUG == '1'
run: |
echo "GITHUB_EVENT_NAME: ${{ github.event_name }}"
echo "GITHUB_CONTEXT: ${{ toJson(github.event) }}"
- name: Get metadata (push)
if: github.event_name == 'push'
run: |
NUMBER_OF_COMMITS=$(printf "%s\n" '${{ toJson(github.event.commits.*.id) }}' | jq length)
echo "There are $NUMBER_OF_COMMITS commits in this push."
echo "BASE_COMMIT=$(git rev-parse HEAD~$NUMBER_OF_COMMITS)" >> $GITHUB_ENV
- name: Get metadata (pull_request)
if: github.event_name == 'pull_request'
run: |
BASE_COMMIT=$(curl --location --request GET 'https://api.github.com/repos/TryGhost/Ghost/pulls/${{ github.event.pull_request.number }}' --header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' | jq -r .base.sha)
echo "Setting BASE_COMMIT to $BASE_COMMIT"
echo "BASE_COMMIT=$BASE_COMMIT" >> $GITHUB_ENV
- name: Check user org membership
id: check_user_org_membership
if: github.event_name == 'pull_request'
run: |
echo "Looking up: ${{ github.triggering_actor }}"
ENCODED_USERNAME=$(printf '%s' '${{ github.triggering_actor }}' | jq -sRr @uri)
LOOKUP_USER=$(curl --write-out "%{http_code}" --silent --output /dev/null --location "https://api.github.com/orgs/tryghost/members/$ENCODED_USERNAME" --header "Authorization: Bearer ${{ secrets.CANARY_DOCKER_BUILD }}")
if [ "$LOOKUP_USER" == "204" ]; then
echo "User is in the org"
echo "is_member=true" >> $GITHUB_OUTPUT
else
echo "User is not in the org"
echo "is_member=false" >> $GITHUB_OUTPUT
fi
- name: Determine added packages
uses: dorny/[email protected]
id: added
with:
filters: |
new-package:
- added: 'ghost/**/package.json'
- name: Determine changed packages
uses: AurorNZ/[email protected]
id: changed
with:
filters: |
shared: &shared
- '.github/**'
- 'package.json'
- 'yarn.lock'
core:
- *shared
- 'ghost/**'
- '!ghost/admin/**'
- '!ghost/core/core/server/data/tinybird/**'
admin:
- *shared
- 'ghost/admin/**'
admin-x-settings:
- *shared
- 'apps/admin-x-settings/**'
- 'apps/admin-x-design-system/**'
- 'apps/admin-x-framework/**'
- 'apps/shade/**'
activitypub:
- *shared
- 'apps/shade/**'
- 'apps/admin-x-framework/**'
- 'apps/activitypub/**'
announcement-bar:
- *shared
- 'apps/announcement-bar/**'
comments-ui:
- *shared
- 'apps/comments-ui/**'
portal:
- *shared
- 'apps/portal/**'
signup-form:
- *shared
- 'apps/signup-form/**'
sodo-search:
- *shared
- 'apps/sodo-search/**'
tinybird:
- 'ghost/core/core/server/data/tinybird/**'
- '!ghost/core/core/server/data/tinybird/**/*.md'
any-code:
- '!**/*.md'
- name: Compute lockfile hash
run: echo "hash=lockfile-${{ hashFiles('yarn.lock') }}" >> "$GITHUB_ENV"
- name: Compute dependency cache key
run: echo "cachekey=dep-cache-${{ hashFiles('yarn.lock') }}-${{ env.HEAD_COMMIT }}" >> "$GITHUB_ENV"
- name: Compute dependency cache restore key
run: |
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "DEPENDENCY_CACHE_RESTORE_KEYS<<$EOF" >> "$GITHUB_ENV"
echo "dep-cache-${{ env.hash }}-${{ github.sha }}" >> "$GITHUB_ENV"
echo "dep-cache-${{ env.hash }}" >> "$GITHUB_ENV"
echo "dep-cache" >> "$GITHUB_ENV"
echo "$EOF" >> "$GITHUB_ENV"
- name: Nx cache
uses: actions/cache@v4
id: cache_nx
with:
path: .nxcache
key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT }}
restore-keys: |
nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT }}
nx-Linux-${{ github.ref }}
nx-Linux
- name: Check dependency cache
uses: actions/cache@v4
id: cache_dependencies
with:
path: ${{ env.CACHED_DEPENDENCY_PATHS }}
key: ${{ env.cachekey }}
restore-keys: ${{ env.IS_DEVELOPMENT == 'false' && env.DEPENDENCY_CACHE_RESTORE_KEYS || 'dep-never-restore'}}
- name: Define Node test matrix
id: node_matrix
run: |
echo 'matrix=["22.18.0"]' >> $GITHUB_OUTPUT
- name: Set up Node
uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: bash .github/scripts/install-deps.sh
outputs:
changed_admin: ${{ steps.changed.outputs.admin }}
changed_core: ${{ steps.changed.outputs.core }}
changed_admin_x_settings: ${{ steps.changed.outputs.admin-x-settings }}
changed_activitypub: ${{ steps.changed.outputs.activitypub }}
changed_announcement_bar: ${{ steps.changed.outputs.announcement-bar }}
changed_comments_ui: ${{ steps.changed.outputs.comments-ui }}
changed_portal: ${{ steps.changed.outputs.portal }}
changed_signup_form: ${{ steps.changed.outputs.signup-form }}
changed_sodo_search: ${{ steps.changed.outputs.sodo-search }}
changed_tinybird: ${{ steps.changed.outputs.tinybird }}
changed_any_code: ${{ steps.changed.outputs.any-code }}
changed_new_package: ${{ steps.added.outputs.new-package }}
base_commit: ${{ env.BASE_COMMIT }}
is_main: ${{ env.IS_MAIN }}
is_development: ${{ env.IS_DEVELOPMENT }}
is_six: ${{ env.IS_SIX }}
is_six_pr: ${{ env.IS_SIX_PR }}
member_is_in_org: ${{ steps.check_user_org_membership.outputs.is_member }}
has_browser_tests_label: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'browser-tests') }}
dependency_cache_key: ${{ env.cachekey }}
node_version: ${{ env.NODE_VERSION }}
node_test_matrix: ${{ steps.node_matrix.outputs.matrix }}
job_lint:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_any_code == 'true'
name: Lint
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1000
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- uses: actions/cache@v4
with:
path: ghost/**/.eslintcache
key: eslint-cache
- run: yarn nx affected -t lint --base=${{ needs.job_setup.outputs.BASE_COMMIT }}
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_i18n:
runs-on: ubuntu-latest
needs: [job_setup]
name: i18n
if: |
needs.job_setup.outputs.changed_comments_ui == 'true'
|| needs.job_setup.outputs.changed_signup_form == 'true'
|| needs.job_setup.outputs.changed_sodo_search == 'true'
|| needs.job_setup.outputs.changed_portal == 'true'
|| needs.job_setup.outputs.changed_core == 'true'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Run i18n tests
run: yarn nx run @tryghost/i18n:test
job_admin-tests:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_admin == 'true'
name: Admin tests - Chrome
env:
MOZ_HEADLESS: 1
JOBS: 1
CI: true
COVERAGE: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- run: yarn nx run ghost-admin:test
env:
BROWSER: Chrome
# Merge coverage reports and upload
- name: Merge Admin test coverage
run: yarn ember coverage-merge
working-directory: ghost/admin
- uses: actions/upload-artifact@v4
with:
name: admin-coverage
path: ghost/*/coverage/cobertura-coverage.xml
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_browser-tests:
name: Browser tests
timeout-minutes: 60
runs-on:
labels: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_any_code == 'true' && (needs.job_setup.outputs.is_six_pr == 'true' || needs.job_setup.outputs.is_development == 'true' || needs.job_setup.outputs.has_browser_tests_label == 'true')
concurrency:
group: ${{ github.workflow }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Check secrets
if: github.event_name == 'pull_request'
env:
STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }}
run: |
if [ -z "${{ env.STRIPE_PUBLISHABLE_KEY }}" ]; then
echo "Stripe Publishable Key is not available. Did you open this PR from a fork?"
echo "If so, please re-open the PR from a branch in the upstream TryGhost/Ghost repository."
exit 1
fi
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn
- name: Install Stripe-CLI
run: |
export VERSION=1.13.5
wget "https://github.com/stripe/stripe-cli/releases/download/v$VERSION/stripe_${VERSION}_linux_x86_64.tar.gz"
tar -zxvf "stripe_${VERSION}_linux_x86_64.tar.gz"
mv stripe /usr/local/bin
stripe -v
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Run migrations
working-directory: ghost/core
run: yarn knex-migrator init
- name: Setup Playwright
uses: ./.github/actions/setup-playwright
- name: Build Admin
run: yarn nx run ghost-admin:build:dev
- name: Run Playwright tests locally
run: yarn test:browser
env:
CI: true
STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: browser-tests-playwright-report
path: ghost/core/playwright-report
retention-days: 30
job_perf-tests:
runs-on:
labels: ubuntu-latest-4-cores
needs: [job_setup]
if: needs.job_setup.outputs.changed_core == 'true' && needs.job_setup.outputs.is_development == 'true'
name: Performance tests
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Install hyperfine
run: |
export HYPERFINE_VERSION=1.18.0
wget https://github.com/sharkdp/hyperfine/releases/download/v$HYPERFINE_VERSION/hyperfine-v$HYPERFINE_VERSION-x86_64-unknown-linux-gnu.tar.gz
tar -zxvf hyperfine-v$HYPERFINE_VERSION-x86_64-unknown-linux-gnu.tar.gz
mv hyperfine-v$HYPERFINE_VERSION-x86_64-unknown-linux-gnu/hyperfine /usr/local/bin
chmod +x /usr/local/bin/hyperfine
- name: Build TS code
run: yarn nx run-many -t build:tsc
- name: Run hyperfine on boot
working-directory: ghost/core
run: hyperfine --show-output --warmup 3 'GHOST_CI_SHUTDOWN_AFTER_BOOT=1 node index.js' --export-json boot-perf.json
- name: Convert data
working-directory: ghost/core
run: |
jq '[{ name: "Boot time", unit: "s", value: .results[0].median, range: ((.results[0].max - .results[0].min) | tostring) }]' < boot-perf.json > boot-perf-formatted.json
- name: Run analysis
uses: benchmark-action/[email protected]
with:
tool: 'customSmallerIsBetter'
output-file-path: ghost/core/boot-perf-formatted.json
benchmark-data-dir-path: ""
gh-repository: github.com/TryGhost/Ghost-Benchmarks
github-token: ${{ secrets.CANARY_DOCKER_BUILD }}
auto-push: true
job_unit-tests:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_any_code == 'true'
strategy:
matrix:
node: ${{ fromJSON(needs.job_setup.outputs.node_test_matrix) }}
name: Unit tests (Node ${{ matrix.node }})
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1000
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ matrix.node }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Set timezone (non-UTC)
uses: szenius/[email protected]
with:
timezoneLinux: "America/New_York"
# Ensure all built packages are built before running tests (admin is built in job_setup)
- name: Build remaining assets
run: yarn nx run-many -t build --exclude=ghost-admin
- run: yarn nx affected -t test:unit --base=${{ needs.job_setup.outputs.BASE_COMMIT }}
- uses: actions/upload-artifact@v4
if: matrix.node == env.NODE_VERSION
with:
name: unit-coverage
path: ghost/*/coverage/cobertura-coverage.xml
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_acceptance-tests:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_core == 'true'
strategy:
matrix:
node: ${{ fromJSON(needs.job_setup.outputs.node_test_matrix) }}
env:
- DB: mysql8
NODE_ENV: testing-mysql
include:
- node: ${{ needs.job_setup.outputs.node_version }}
env:
DB: sqlite3
NODE_ENV: testing
env:
DB: ${{ matrix.env.DB }}
NODE_ENV: ${{ matrix.env.NODE_ENV }}
name: Acceptance tests (Node ${{ matrix.node }}, ${{ matrix.env.DB }})
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ matrix.node }}
- name: Shutdown MySQL
run: sudo service mysql stop
if: matrix.env.DB == 'mysql8'
- name: Login to Docker Hub
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: tryghost/mysql-action@main
if: matrix.env.DB == 'mysql8'
timeout-minutes: 3
with:
authentication plugin: 'caching_sha2_password'
mysql version: '8.0'
mysql database: 'ghost_testing'
mysql root password: 'root'
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Set timezone (non-UTC)
uses: szenius/[email protected]
with:
timezoneLinux: "America/New_York"
- name: Set env vars (SQLite)
if: contains(matrix.env.DB, 'sqlite')
run: echo "database__connection__filename=/dev/shm/ghost-test.db" >> $GITHUB_ENV
- name: Set env vars (MySQL)
if: contains(matrix.env.DB, 'mysql')
run: echo "database__connection__password=root" >> $GITHUB_ENV
- name: E2E tests
working-directory: ghost/core
run: yarn test:ci:e2e
- name: Integration tests
working-directory: ghost/core
run: yarn test:ci:integration
- uses: actions/upload-artifact@v4
if: matrix.node == env.NODE_VERSION && contains(matrix.env.DB, 'mysql')
with:
name: e2e-coverage
path: |
ghost/*/coverage-e2e/cobertura-coverage.xml
ghost/*/coverage-integration/cobertura-coverage.xml
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_legacy-tests:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_core == 'true'
strategy:
matrix:
include:
- node: ${{ needs.job_setup.outputs.node_version }}
env:
DB: mysql8
NODE_ENV: testing-mysql
- node: ${{ needs.job_setup.outputs.node_version }}
env:
DB: sqlite3
NODE_ENV: testing
env:
DB: ${{ matrix.env.DB }}
NODE_ENV: ${{ matrix.env.NODE_ENV }}
name: Legacy tests (Node ${{ matrix.node }}, ${{ matrix.env.DB }})
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ matrix.node }}
- name: Shutdown MySQL
run: sudo service mysql stop
if: matrix.env.DB == 'mysql8'
- uses: tryghost/mysql-action@main
if: matrix.env.DB == 'mysql8'
timeout-minutes: 3
with:
authentication plugin: 'caching_sha2_password'
mysql version: '8.0'
mysql database: 'ghost_testing'
mysql root password: 'root'
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Set env vars (SQLite)
if: contains(matrix.env.DB, 'sqlite')
run: echo "database__connection__filename=/dev/shm/ghost-test.db" >> $GITHUB_ENV
- name: Set env vars (MySQL)
if: contains(matrix.env.DB, 'mysql')
run: echo "database__connection__password=root" >> $GITHUB_ENV
- name: Legacy tests
working-directory: ghost/core
run: yarn test:ci:legacy
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_admin_x_settings:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_admin_x_settings == 'true'
name: Admin-X Settings tests
env:
CI: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Setup Playwright
uses: ./.github/actions/setup-playwright
- run: yarn nx run @tryghost/admin-x-settings:test:acceptance
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: admin-x-settings-playwright-report
path: apps/admin-x-settings/playwright-report
retention-days: 30
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_activitypub:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_activitypub == 'true'
name: ActivityPub tests
env:
CI: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Setup Playwright
uses: ./.github/actions/setup-playwright
- run: yarn nx run @tryghost/activitypub:test:acceptance
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: activitypub-playwright-report
path: apps/activitypub/playwright-report
retention-days: 30
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_comments_ui:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_comments_ui == 'true'
name: Comments-UI tests
env:
CI: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Setup Playwright
uses: ./.github/actions/setup-playwright
- run: yarn nx run @tryghost/comments-ui:test
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: comments-ui-playwright-report
path: apps/comments-ui/playwright-report
retention-days: 30
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_signup_form:
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_signup_form == 'true'
name: Signup-form tests
env:
CI: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Setup Playwright
uses: ./.github/actions/setup-playwright
- run: yarn nx run @tryghost/signup-form:test:e2e
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: signup-form-playwright-report
path: apps/signup-form/playwright-report
retention-days: 30
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_tinybird-tests:
name: Tinybird Tests
runs-on: ubuntu-latest
needs: [job_setup]
if: needs.job_setup.outputs.changed_tinybird == 'true'
defaults:
run:
working-directory: ghost/core/core/server/data/tinybird
services:
tinybird:
image: tinybirdco/tinybird-local:latest
ports:
- 7181:7181
env:
TINYBIRD_HOST: ${{ secrets.TINYBIRD_HOST }}
TINYBIRD_TOKEN: ${{ secrets.TINYBIRD_TOKEN }}
TINYBIRD_HOST_STAGING: ${{ secrets.TINYBIRD_HOST_STAGING }}
TINYBIRD_TOKEN_STAGING: ${{ secrets.TINYBIRD_TOKEN_STAGING }}
steps:
- uses: actions/checkout@v4
- name: Install Tinybird CLI
run: curl -fsSL https://tinybird.co/install.sh | sh
- name: Build project
run: tb build
- name: Test project
run: tb test run
- name: Deployment check - Staging
run: tb --cloud --host ${{ env.TINYBIRD_HOST_STAGING }} --token ${{ env.TINYBIRD_TOKEN_STAGING }} deploy --check
- name: Deployment check - Production
run: tb --cloud --host ${{ env.TINYBIRD_HOST }} --token ${{ env.TINYBIRD_TOKEN }} deploy --check
job_ghost-cli:
name: Ghost-CLI tests
needs: [job_setup]
if: needs.job_setup.outputs.changed_core == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install npm v8 # downgrade from v10 to v8 due to https://github.com/npm/cli/issues/6738
run: npm install -g npm@8
- name: Install Ghost-CLI
run: npm install -g ghost-cli@latest
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- run: node .github/scripts/bump-version.js canary
- run: yarn archive
- run: mv ghost-*.tgz ghost.tgz
working-directory: ghost/core
- name: Switch back to Node v16.14.0 (for v4)
uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: '16.14.0'
- name: Install latest v4
run: |
DIR=$(mktemp -d)
echo "V4_DIR=$DIR" >> $GITHUB_ENV
ghost install v4 --local -d $DIR
- name: Switch back to ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Update from v4
run: |
ghost update -f -d $V4_DIR --archive $(pwd)/ghost/core/ghost.tgz
- name: Save Ghost CLI Debug Logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: ghost-cli-debug-logs
path: /home/runner/.ghost/logs/
- name: Clean Install
run: |
DIR=$(mktemp -d)
ghost install local -d $DIR --archive $(pwd)/ghost/core/ghost.tgz
- name: Latest Release
run: |
DIR=$(mktemp -d)
ghost install local -d $DIR
ghost update -d $DIR --archive $(pwd)/ghost/core/ghost.tgz
- name: Print debug logs
if: failure()
run: |
[ -f ~/.ghost/logs/*.log ] && cat ~/.ghost/logs/*.log
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_docker_build:
name: Build & Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Determine build strategy
id: strategy
run: |
IS_FORK_PR="false"
if [ "${{ github.event_name }}" = "pull_request" ] && [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
IS_FORK_PR="true"
fi
IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/ghost-development"
if [ "$IS_FORK_PR" = "true" ]; then
IMAGE_NAME="ghcr.io/${{ github.event.pull_request.head.repo.owner.login }}/ghost-development"
fi
CACHE_KEY=$(echo $IMAGE_NAME | tr '[:upper:]' '[:lower:]')
echo "is-fork-pr=$IS_FORK_PR" >> $GITHUB_OUTPUT
echo "should-push=$( [ "$IS_FORK_PR" = "false" ] && echo "true" || echo "false" )" >> $GITHUB_OUTPUT
echo "should-load=$( [ "$IS_FORK_PR" = "true" ] && echo "true" || echo "false" )" >> $GITHUB_OUTPUT
echo "image-name=$IMAGE_NAME" >> $GITHUB_OUTPUT
echo "cache-key=$CACHE_KEY" >> $GITHUB_OUTPUT
echo "Build Strategy: "
echo " Is fork PR: $IS_FORK_PR"
echo " Should push: $( [ "$IS_FORK_PR" = "false" ] && echo "true" || echo "false" )"
echo " Should load: $( [ "$IS_FORK_PR" = "true" ] && echo "true" || echo "false" )"
echo " Image name: $IMAGE_NAME"
echo " Cache key: $CACHE_KEY"
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ steps.strategy.outputs.image-name }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha
type=raw,value=latest,enable={{is_default_branch}}
labels: |
org.opencontainers.image.title=Ghost Development
org.opencontainers.image.description=Ghost development build
org.opencontainers.image.vendor=TryGhost
maintainer=TryGhost
- name: Build and push Docker image
uses: docker/build-push-action@v6
id: build
with:
context: .
file: Dockerfile
push: ${{ steps.strategy.outputs.should-push }}
load: ${{ steps.strategy.outputs.should-load }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# On PRs: use both main cache and PR-specific cache
# On main: only use main cache
cache-from: |
type=registry,ref=${{ steps.strategy.outputs.cache-key }}:cache-main
${{ github.event_name == 'pull_request' && format('type=registry,ref={0}:cache-pr-{1}', steps.strategy.outputs.cache-key, github.event.pull_request.number) || '' }}
# Only export cache if we can push (not on fork PRs)
cache-to: ${{ steps.strategy.outputs.should-push == 'true' && format('type=registry,ref={0}:cache-{1},mode=max', steps.strategy.outputs.cache-key, github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'main') || '' }}
- name: Save image as artifact (fork PR)
if: steps.strategy.outputs.is-fork-pr == 'true'
run: |
# Get the first tag from the multi-line tags output
IMAGE_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1)
echo "Saving image: $IMAGE_TAG"
docker save "$IMAGE_TAG" | gzip > docker-image.tar.gz
echo "Image saved as docker-image.tar.gz"
ls -lh docker-image.tar.gz
- name: Upload image artifact (fork PR)
if: steps.strategy.outputs.is-fork-pr == 'true'
uses: actions/upload-artifact@v4
with:
name: docker-image
path: docker-image.tar.gz
retention-days: 1
outputs:
image-tags: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
is-fork: ${{ steps.strategy.outputs.is-fork-pr }}
job_inspect_image:
name: Inspect Docker Image
needs: job_docker_build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
sparse-checkout: |
.github/actions/load-docker-image
- name: Load Docker Image
id: load
uses: ./.github/actions/load-docker-image
with:
is-fork: ${{ needs.job_docker_build.outputs.is-fork }}
image-tags: ${{ needs.job_docker_build.outputs.image-tags }}
- name: Inspect image size and layers
shell: bash
run: |
IMAGE_TAG="${{ steps.load.outputs.image-tag }}"
echo "Analyzing Docker image: $IMAGE_TAG"
# Get the image size in bytes
IMAGE_SIZE_BYTES=$(docker inspect "$IMAGE_TAG" --format='{{.Size}}')
# Convert to human readable format
IMAGE_SIZE_MB=$(( IMAGE_SIZE_BYTES / 1024 / 1024 ))
IMAGE_SIZE_GB=$(echo "scale=2; $IMAGE_SIZE_BYTES / 1024 / 1024 / 1024" | bc)
# Format size display based on magnitude
if [ $IMAGE_SIZE_MB -ge 1024 ]; then
IMAGE_SIZE_DISPLAY="${IMAGE_SIZE_GB} GB"
else
IMAGE_SIZE_DISPLAY="${IMAGE_SIZE_MB} MB"
fi
echo "Image size: ${IMAGE_SIZE_DISPLAY}"
# Write to GitHub Step Summary
{
echo "# Docker Image Analysis"
echo ""
echo "**Image:** \`$IMAGE_TAG\`"
echo ""
echo "**Total Size:** ${IMAGE_SIZE_DISPLAY}"
echo ""
echo "## Image Layers"
echo ""
echo "| Size | Layer |"
echo "|------|-------|"
# Get all layers (including 0B ones)
docker history "$IMAGE_TAG" --format "{{.Size}}@@@{{.CreatedBy}}" --no-trunc | \
while IFS='@@@' read -r size cmd; do
# Clean up the command for display
cmd_clean=$(echo "$cmd" | sed 's/^\/bin\/sh -c //' | sed 's/^#(nop) //' | sed 's/^@@//' | sed 's/|/\\|/g' | cut -c1-80)
if [ ${#cmd} -gt 80 ]; then
cmd_clean="${cmd_clean}..."
fi
echo "| $size | \`${cmd_clean}\` |"
done
} >> $GITHUB_STEP_SUMMARY
job_e2e_tests:
name: ${{matrix.shell == 'react' && '[Optional] ' || ''}}E2E Tests (${{ matrix.shell == 'react' && 'React' || 'Ember' }} ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
runs-on: ubuntu-latest
needs: [job_docker_build, job_setup]
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
shell: [ember, react]
continue-on-error: ${{ matrix.shell == 'react' }}
steps:
- name: Checkout
uses: actions/checkout@v4
# TODO: Build tb-cli in a separate workflow and pull from GHCR instead of building here
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Tinybird CLI Image
uses: docker/build-push-action@v6
id: build
with:
context: .
file: docker/tb-cli/Dockerfile
push: false
load: true
tags: ghost-tb-cli
- name: Load Image
uses: ./.github/actions/load-docker-image
id: load
with:
is-fork: ${{ needs.job_docker_build.outputs.is-fork }}
image-tags: ${{ needs.job_docker_build.outputs.image-tags }}
- name: Setup Docker Registry Mirrors
uses: ./.github/actions/setup-docker-registry-mirrors
- name: Pull images
env:
GHOST_IMAGE_TAG: ${{ steps.load.outputs.image-tag }}
run: docker compose -f e2e/compose.yml pull
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Setup Playwright
uses: ./.github/actions/setup-playwright
- name: Run e2e tests
env:
GHOST_IMAGE_TAG: ${{ steps.load.outputs.image-tag }}
USE_REACT_SHELL: ${{ matrix.shell == 'react' && 'true' || '' }}
TEST_WORKERS_COUNT: 1
run: yarn test:e2e --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload blob report to GitHub Actions Artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shell }}-${{ matrix.shardIndex }}
path: e2e/blob-report
retention-days: 1
- name: Upload test results artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.shell }}-${{ matrix.shardIndex }}
path: e2e/test-results
retention-days: 7
- uses: tryghost/actions/actions/slack-build@main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
with:
status: ${{ job.status }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_merge_e2e_reports:
name: Merge ${{ matrix.shell == 'react' && 'React' || 'Ember' }} Reports
if: always()
needs: [job_e2e_tests, job_setup]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shell: [ember, react]
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v4
continue-on-error: true
with:
path: e2e/all-blob-reports
pattern: blob-report-${{ matrix.shell }}-*
merge-multiple: true
- name: Check for blob reports
id: check
run: |
if [ -d "e2e/all-blob-reports" ] && [ -n "$(ls -A e2e/all-blob-reports 2>/dev/null)" ]; then
echo "has_reports=true" >> $GITHUB_OUTPUT
else
echo "has_reports=false" >> $GITHUB_OUTPUT
fi
- name: Download test results from GitHub Actions Artifacts
if: steps.check.outputs.has_reports == 'true'
uses: actions/download-artifact@v4
with:
path: e2e/all-test-results
pattern: test-results-${{ matrix.shell }}-*
merge-multiple: true
- name: Merge into HTML Report
if: steps.check.outputs.has_reports == 'true'
run: npx playwright merge-reports --reporter html ./all-blob-reports
working-directory: e2e
- name: Upload HTML report
if: steps.check.outputs.has_reports == 'true'
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.shell }}
path: e2e/playwright-report
retention-days: 14
- name: Upload merged test results
if: steps.check.outputs.has_reports == 'true'
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.shell }}
path: e2e/all-test-results
retention-days: 7
- name: View Test Report command
if: steps.check.outputs.has_reports == 'true'
run: |
echo -e "::notice::To view the ${{ matrix.shell == 'react' && 'React' || 'Ember' }} Playwright report locally, run:\n\nREPORT_DIR=\$(mktemp -d) && gh run download ${{ github.run_id }} -n playwright-report-${{ matrix.shell }} -D \"\$REPORT_DIR\" && npx playwright show-report \"\$REPORT_DIR\""
- name: Comment on PR with test report command
if: github.event_name == 'pull_request' && steps.check.outputs.has_reports == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr comment ${{ github.event.pull_request.number }} --body "## ${{ matrix.shell == 'react' && 'React' || 'Ember' }} E2E Tests Failed
To view the Playwright test report locally, run:
\`\`\`bash
REPORT_DIR=\$(mktemp -d) && gh run download ${{ github.run_id }} -n playwright-report-${{ matrix.shell }} -D \"\$REPORT_DIR\" && npx playwright show-report \"\$REPORT_DIR\"
\`\`\`"
job_coverage:
name: Coverage
needs: [
job_admin-tests,
job_acceptance-tests,
job_unit-tests
]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Restore Admin coverage
if: contains(needs.job_admin-tests.result, 'success')
uses: actions/download-artifact@v4
with:
name: admin-coverage
- name: Move coverage
if: contains(needs.job_admin-tests.result, 'success')
run: |
rsync -av --remove-source-files admin/* ghost/admin
- name: Upload Admin test coverage
uses: codecov/codecov-action@v5
with:
flags: admin-tests
- name: Restore E2E coverage
if: contains(needs.job_acceptance-tests.result, 'success')
uses: actions/download-artifact@v4
with:
name: e2e-coverage
- name: Move coverage
if: contains(needs.job_acceptance-tests.result, 'success')
run: |
rsync -av --remove-source-files core/* ghost/core
- name: Upload E2E test coverage
if: contains(needs.job_acceptance-tests.result, 'success')
uses: codecov/codecov-action@v5
with:
flags: e2e-tests
job_required_tests:
name: All required tests passed or skipped
needs:
[
job_setup,
job_lint,
job_i18n,
job_ghost-cli,
job_admin-tests,
job_unit-tests,
job_acceptance-tests,
job_legacy-tests,
job_browser-tests,
job_admin_x_settings,
job_activitypub,
job_comments_ui,
job_signup_form,
job_tinybird-tests,
job_e2e_tests
]
if: always()
runs-on: ubuntu-latest
steps:
- name: Output needs
run: echo "${{ toJson(needs) }}"
- name: Check if any required jobs failed or been cancelled
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: |
echo "One of the dependent jobs have failed or been cancelled. You may need to re-run it." && exit 1
canary:
needs: [
job_setup,
job_required_tests
]
name: Canary
runs-on: ubuntu-latest
if: |
always()
&& needs.job_setup.result == 'success'
&& needs.job_required_tests.result == 'success'
&& (
needs.job_setup.outputs.is_main == 'true'
|| needs.job_setup.outputs.is_six == 'true'
|| (
github.event_name == 'pull_request'
&& (
needs.job_setup.outputs.member_is_in_org == 'true'
|| github.event.pull_request.user.login == 'renovate[bot]'
)
&& contains(github.event.pull_request.labels.*.name, 'deploy-to-staging')
)
)
steps:
- name: Output needs (for debugging)
run: echo "${{ toJson(needs) }}"
- name: Compute branch name (push)
if: github.event_name == 'push'
run: echo "branch_name=${{ github.ref_name }}" >> $GITHUB_ENV
- name: Compute branch name (pull_request)
if: github.event_name == 'pull_request'
run: echo "branch_name=${{ github.ref }}" >> $GITHUB_ENV
- name: Set deployment parameters
run: |
if [[ "${{ needs.job_setup.outputs.is_main }}" == "true" ]]; then
echo "deploy_version=canary" >> $GITHUB_ENV
else
echo "deploy_version=six" >> $GITHUB_ENV
fi
- name: Invoke build
uses: aurelien-baudet/workflow-dispatch@v4
with:
token: ${{ secrets.CANARY_DOCKER_BUILD }}
workflow: .github/workflows/deploy.yml
ref: 'refs/heads/main' # this is the ref of Ghost-Moya
repo: TryGhost/Ghost-Moya
# env.branch_name is the branch of Ghost itself
inputs: '{"version":"${{ env.deploy_version }}","environment":"staging","version_extra":"${{ env.branch_name }}"}'
wait-for-completion-timeout: 25m
wait-for-completion-interval: 30s
publish_packages:
needs: [
job_setup,
job_lint,
job_unit-tests
]
name: Publish ${{ matrix.package_name }}
runs-on: ubuntu-latest
if: always() && needs.job_setup.result == 'success' && needs.job_lint.result == 'success' && needs.job_unit-tests.result == 'success' && needs.job_setup.outputs.is_main == 'true'
permissions:
id-token: write
strategy:
matrix:
include:
- package_name: '@tryghost/activitypub'
package_path: 'apps/activitypub'
cdn_paths: 'https://cdn.jsdelivr.net/ghost/activitypub@CURRENT_MAJOR/dist/activitypub.js'
- package_name: '@tryghost/portal'
package_path: 'apps/portal'
cdn_paths: 'https://cdn.jsdelivr.net/ghost/portal@~CURRENT_MINOR/umd/portal.min.js'
- package_name: '@tryghost/sodo-search'
package_path: 'apps/sodo-search'
cdn_paths: |
https://cdn.jsdelivr.net/ghost/sodo-search@~CURRENT_MINOR/umd/sodo-search.min.js
https://cdn.jsdelivr.net/ghost/sodo-search@~CURRENT_MINOR/umd/main.css
- package_name: '@tryghost/comments-ui'
package_path: 'apps/comments-ui'
cdn_paths: 'https://cdn.jsdelivr.net/ghost/comments-ui@~CURRENT_MINOR/umd/comments-ui.min.js'
- package_name: '@tryghost/signup-form'
package_path: 'apps/signup-form'
cdn_paths: 'https://cdn.jsdelivr.net/ghost/signup-form@~CURRENT_MINOR/umd/signup-form.min.js'
- package_name: '@tryghost/announcement-bar'
package_path: 'apps/announcement-bar'
cdn_paths: 'https://cdn.jsdelivr.net/ghost/announcement-bar@~CURRENT_MINOR/umd/announcement-bar.min.js'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Check if version changed
id: version_check
working-directory: ${{ matrix.package_path }}
run: |
CURRENT_VERSION=$(cat package.json | jq -r .version)
PUBLISHED_VERSION=$(npm show ${{ matrix.package_name }} version || echo "0.0.0")
echo "Current version: $CURRENT_VERSION"
echo "Published version: $PUBLISHED_VERSION"
CURRENT_MINOR=$(cat package.json | jq -r .version | awk -F. '{print $1"."$2}')
echo "current_minor=$CURRENT_MINOR" >> $GITHUB_OUTPUT
CURRENT_MAJOR=$(cat package.json | jq -r .version | awk -F. '{print $1}')
echo "current_major=$CURRENT_MAJOR" >> $GITHUB_OUTPUT
if [ "$CURRENT_VERSION" = "$PUBLISHED_VERSION" ]; then
echo "Version is unchanged."
echo "version_changed=false" >> $GITHUB_OUTPUT
else
echo "Version has changed."
echo "version_changed=true" >> $GITHUB_OUTPUT
fi
- name: Build the package
if: steps.version_check.outputs.version_changed == 'true'
run: yarn run nx build ${{ matrix.package_name }}
- name: Configure .npmrc
if: steps.version_check.outputs.version_changed == 'true'
run: |
echo "@tryghost:registry=https://registry.npmjs.org/" >> ~/.npmrc
# TODO: Check we can remove this once we update Node to v24
- name: Install v11 of NPM # We need this to install packages via OIDC.
if: steps.version_check.outputs.version_changed == 'true'
run: npm install -g npm@11
- name: Publish to npm
if: steps.version_check.outputs.version_changed == 'true'
working-directory: ${{ matrix.package_path }}
run: npm publish --access public
- name: Replace version placeholders in cdn-paths
id: cdn_paths
if: steps.version_check.outputs.version_changed == 'true'
run: |
cdn_paths="${{ matrix.cdn_paths }}"
echo "cdn_paths<<EOF" >> $GITHUB_OUTPUT
echo "$cdn_paths" | sed -e 's/CURRENT_MINOR/${{ steps.version_check.outputs.current_minor }}/g' -e 's/CURRENT_MAJOR/${{ steps.version_check.outputs.current_major }}/g' >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Print cdn_paths
if: steps.version_check.outputs.version_changed == 'true'
run: echo "${{ steps.cdn_paths.outputs.cdn_paths }}"
- name: Wait before purging jsDelivr cache
if: steps.version_check.outputs.version_changed == 'true' && matrix.package_name == '@tryghost/activitypub'
run: |
echo "Purging jsDelivr cache immediately after publishing a new version on NPM is unreliable. Waiting 1 minute before purging cache..."
sleep 60
- name: Purge jsDelivr cache
if: steps.version_check.outputs.version_changed == 'true'
uses: gacts/purge-jsdelivr-cache@v1
with:
url: ${{ steps.cdn_paths.outputs.cdn_paths }}
deploy_tinybird_staging:
name: Deploy Tinybird - Staging
runs-on: ubuntu-latest
needs: [
job_setup,
job_tinybird-tests
]
if: always() && github.event_name == 'push' && needs.job_setup.outputs.changed_tinybird == 'true' && needs.job_setup.result == 'success' && needs.job_tinybird-tests.result == 'success' && needs.job_setup.outputs.is_main == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy to Staging
uses: ./.github/actions/deploy-tinybird
with:
host: ${{ secrets.TINYBIRD_HOST_STAGING }}
token: ${{ secrets.TINYBIRD_TOKEN_STAGING }}
workspace: 'Staging'
slack-webhook: ${{ secrets.ANALYTICS_SLACK_WEBHOOK_URL }}
deploy_tinybird_production:
name: Deploy Tinybird - Production
runs-on: ubuntu-latest
needs: [
job_setup,
job_tinybird-tests,
deploy_tinybird_staging
]
if: always() && github.event_name == 'push' && needs.job_setup.outputs.changed_tinybird == 'true' && needs.job_setup.result == 'success' && needs.job_tinybird-tests.result == 'success' && needs.deploy_tinybird_staging.result == 'success' && needs.job_setup.outputs.is_main == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy to Production
uses: ./.github/actions/deploy-tinybird
with:
host: ${{ secrets.TINYBIRD_HOST }}
token: ${{ secrets.TINYBIRD_TOKEN }}
workspace: 'Production'
slack-webhook: ${{ secrets.ANALYTICS_SLACK_WEBHOOK_URL }}
deploy_admin:
needs: [
job_setup,
job_required_tests
]
name: Deploy Admin
runs-on: ubuntu-latest
if: |
always()
&& needs.job_setup.result == 'success'
&& needs.job_setup.outputs.is_main == 'true'
&& needs.job_required_tests.result == 'success'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
env:
FORCE_COLOR: 0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}
- name: Build Admin
env:
GHOST_CDN_URL: https://assets.ghost.io/admin-forward/
run: yarn nx run admin:build
- name: Upload build artifact
id: upload-artifacts
uses: actions/upload-artifact@v4
with:
name: admin-build
path: apps/admin/dist
- name: Deploy Admin
uses: aurelien-baudet/workflow-dispatch@v4
with:
token: ${{ secrets.CANARY_DOCKER_BUILD }}
workflow: .github/workflows/deploy-admin.yml
ref: 'refs/heads/main' # this is the ref of Ghost-Moya
repo: TryGhost/Ghost-Moya
inputs: '{"admin_build_artifact_id":"${{ steps.upload-artifacts.outputs.artifact-id }}", "admin_build_artifact_run_id":"${{ github.run_id }}"}'
wait-for-completion-timeout: 25m
wait-for-completion-interval: 30s