Skip to content

feat: add framework-agnostic build-and-deploy reusable workflow #78

@kryota-dev

Description

@kryota-dev

Category

New Reusable Workflow

Summary

Add a reusable workflow that combines build and deploy into a single job, eliminating the need for artifact uploads/downloads between jobs.

Motivation

The current architecture separates build and deploy into different jobs, requiring artifacts to pass build output between them:

Current: build job → upload artifact → deploy job (RW) → download artifact → deploy

This causes artifact storage costs that scale with content size. For SSG applications backed by a headless CMS, artifact sizes grow as CMS content increases, and every CMS webhook triggers a rebuild+deploy cycle. This makes artifact storage a significant and ever-growing cost.

By combining build and deploy into a single job within a reusable workflow, artifacts are eliminated entirely:

Proposed: build-and-deploy job (RW) → checkout → build → deploy (no artifacts)

Proposed Implementation

Create .github/workflows/build-and-deploy-web-hosting.yml as a framework-agnostic reusable workflow.

Key Design Principle

The workflow must be framework-agnostic — it does not assume Next.js, Astro, or any specific framework. It simply runs a build command and deploys the output directory.

Inputs

Input Type Required Description
build-command string yes Build command to execute (e.g., pnpm build:next, pnpm build)
output-dir string yes Path to the build output directory (e.g., out, dist)
deploy-type string yes Deployment method (ftp or rsync)
base-path-prefix string no Base path prefix for the deployment
home-url string no Home URL for deployment notifications
dry-run string no Whether to perform a dry run (true/false)
production-branch string no Name of the production branch

Secrets

Same as the existing deploy-web-hosting.yml:

  • server-host, server-user, server-path, server-password, ssh-private-key
  • slack-channel-id, slack-bot-oauth-token, slack-webhook-url, slack-mention-user

Build Environment Variables

Build-time environment variables (CMS keys, feature flags, etc.) should be passed through as secrets or inputs. The exact mechanism needs design consideration — possibly a build-env input or individual secret passthrough.

Internal Flow (single job)

  1. Checkout repository
  2. Setup pnpm (via pnpm-setup composite action)
  3. Restore build cache (.next/cache or equivalent — optional, configurable)
  4. Compute deploy path
  5. Run build-command
  6. Deploy via FTP/rsync
  7. Post Slack notifications
  8. Comment on PR (for PR preview deployments)

Example Caller Workflow

jobs:
  build-and-deploy:
    uses: kryota-dev/actions/.github/workflows/build-and-deploy-web-hosting.yml@vX
    with:
      build-command: 'pnpm build:next'
      output-dir: 'out'
      deploy-type: ${{ vars.DEPLOY_TYPE }}
      base-path-prefix: ${{ vars.NEXT_PUBLIC_BASE_PATH || '' }}
      home-url: ${{ vars.NEXT_PUBLIC_HOME_URL || '' }}
      production-branch: ${{ vars.PRODUCTION_BRANCH }}
    secrets:
      server-host: ${{ secrets.SERVER_HOST }}
      server-user: ${{ secrets.SERVER_USER }}
      # ...

Alternatives Considered

  • Keep current build/deploy separation with artifacts: Simple but incurs growing storage costs proportional to content size.
  • Use actions/cache instead of actions/upload-artifact: Caches are meant for dependencies, not build output. Misusing them could cause other issues.

Additional Context

  • The existing deploy-web-hosting.yml reusable workflow should be kept for backward compatibility during migration, then deprecated.
  • The pnpm-setup composite action can be reused as-is within the new workflow.
  • Build cache (e.g., .next/cache) support should be optional and configurable since not all frameworks use it.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions