Skip to content

Feature Request: Automated PR Preview Deployments with Team Member Validation #19

@IgorShadurin

Description

@IgorShadurin

Overview

We need to implement automated preview deployments for Pull Requests to enable better testing and review processes. These deployments should only trigger for PRs created by team members.

Requirements

  • Automatic deployment of PRs to unique URLs
  • Team member validation before deployment
  • Clean up of preview environments after PR closure
  • Integration with our existing CI/CD pipeline

Implementation Options

1. GitHub-Native Solution

Using GitHub Actions and GitHub Pages:

name: PR Preview Deployment
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  validate-author:
    runs-on: ubuntu-latest
    outputs:
      is-team-member: ${{ steps.check-team.outputs.is_member }}
    steps:
      - name: Check if PR author is team member
        id: check-team
        uses: actions/github-script@v7
        with:
          script: |
            const author = context.payload.pull_request.user.login;
            const org = context.repo.owner;
            try {
              const { data } = await github.rest.teams.getMembershipForUserInOrg({
                org: org,
                team_slug: 'your-team-slug',
                username: author
              });
              return data.state === 'active';
            } catch (error) {
              return false;
            }

  deploy-preview:
    needs: validate-author
    if: needs.validate-author.outputs.is-team-member == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build
        run: npm run build
        env:
          VITE_PR_NUMBER: ${{ github.event.pull_request.number }}
          
      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./dist
          destination_dir: pr-${{ github.event.pull_request.number }}

Configuration:

  1. Enable GitHub Pages in repository settings
  2. Create a team in your organization
  3. Add GITHUB_TOKEN secret with appropriate permissions
  4. Update team slug in the workflow

Preview URL format: https://{org}.github.io/{repo}/pr-{number}/

2. Vercel Integration

Using Vercel for automatic deployments:

  1. Connect GitHub repository to Vercel
  2. Create vercel.json:
{
  "github": {
    "enabled": true,
    "silent": true,
    "autoJobCancelation": true
  },
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/node"
    }
  ]
}
  1. Add team validation with GitHub App:
// api/validate-deployment.js
export default async function handler(req, res) {
  const { author, installationId } = req.body;
  
  const octokit = new Octokit({
    auth: process.env.GITHUB_APP_TOKEN
  });
  
  try {
    const { data } = await octokit.rest.teams.getMembershipForUserInOrg({
      org: 'your-org',
      team_slug: 'your-team',
      username: author
    });
    
    return res.status(200).json({
      proceed: data.state === 'active'
    });
  } catch (error) {
    return res.status(200).json({ proceed: false });
  }
}

3. Netlify Solution

Using Netlify for deployments:

  1. Connect repository to Netlify
  2. Create netlify.toml:
[build]
  command = "npm run build"
  publish = "dist"

[context.deploy-preview]
  command = "npm run build"
  1. Add build hook validation:
// netlify/functions/deploy-validation.js
exports.handler = async (event) => {
  const payload = JSON.parse(event.body);
  const author = payload.review_id ? payload.review.author : payload.pull_request.user.login;
  
  const response = await fetch(
    `https://api.github.com/orgs/${process.env.GITHUB_ORG}/teams/${process.env.TEAM_SLUG}/memberships/${author}`,
    {
      headers: {
        Authorization: `token ${process.env.GITHUB_TOKEN}`,
      },
    }
  );
  
  return {
    statusCode: 200,
    body: JSON.stringify({
      proceed: response.status === 200
    })
  };
};

4. AWS Amplify Approach

Using AWS Amplify for preview deployments:

  1. Connect repository to AWS Amplify
  2. Create amplify.yml:
version: 1
applications:
  - frontend:
      phases:
        preBuild:
          commands:
            - npm ci
        build:
          commands:
            - npm run build
      artifacts:
        baseDirectory: dist
        files:
          - '**/*'
      cache:
        paths:
          - node_modules/**/*
  1. Add Lambda function for team validation:
// amplify/backend/function/validateDeployment/src/index.js
const AWS = require('aws-sdk');
const { Octokit } = require('@octokit/rest');

exports.handler = async (event) => {
  const octokit = new Octokit({
    auth: process.env.GITHUB_TOKEN
  });
  
  const { author } = JSON.parse(event.body);
  
  try {
    const { data } = await octokit.rest.teams.getMembershipForUserInOrg({
      org: process.env.GITHUB_ORG,
      team_slug: process.env.TEAM_SLUG,
      username: author
    });
    
    return {
      statusCode: 200,
      body: JSON.stringify({
        proceed: data.state === 'active'
      })
    };
  } catch (error) {
    return {
      statusCode: 200,
      body: JSON.stringify({
        proceed: false
      })
    };
  }
};

Security Considerations

  1. Use environment-specific secrets
  2. Implement proper token rotation
  3. Use minimal required permissions
  4. Enable branch protection rules
  5. Implement request signing for webhooks

Cleanup Process

  • Implement automatic cleanup of preview environments when PRs are closed
  • Set up retention policies for preview assets
  • Monitor resource usage and costs

Next Steps

  1. Choose preferred deployment solution
  2. Set up required secrets and permissions
  3. Configure team membership
  4. Test with sample PR
  5. Document process for team

Timeline

  • Setup and Configuration: 2 days
  • Implementation: 3 days
  • Testing: 2 days
  • Documentation: 1 day

Please review and provide feedback on the preferred approach.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions