Better Planning with Branch API Timestamps: Know When Your Next Freeze Happens

October 20, 2022

Planning around scheduled freezes just got a whole lot easier! We’re excited to announce that our Branch API endpoints now include next_freeze_at and next_unfreeze_at epoch timestamps, giving you precise visibility into upcoming freeze events.

What’s New

Every Branch API response now includes two powerful new fields:

{
  "frozen": false,
  "allow_deployments": true,
  "branch": "main",
  "repository": "my-app",
  "organization": "my-org",
  "next_freeze_at": 1666310400,
  "next_unfreeze_at": 1666324800,
  "last_updated": "2022-10-20T10:00:00Z"
}

Understanding the Timestamps

  • next_freeze_at: Unix epoch timestamp of the next scheduled freeze
  • next_unfreeze_at: Unix epoch timestamp of the next scheduled unfreeze
  • null values: Returned when no freeze/unfreeze is scheduled

Building Proactive Automation

Predictable Automation

Build smarter CI/CD pipelines that know exactly when freezes will occur:

const response = await fetch('/api/branches/myorg/myrepo/main?access_token=TOKEN');
const branchData = await response.json();

if (branchData.next_freeze_at) {
  const nextFreeze = new Date(branchData.next_freeze_at * 1000);
  const timeUntilFreeze = nextFreeze - new Date();
  
  if (timeUntilFreeze < 30 * 60 * 1000) { // 30 minutes
    console.log('âš ī¸  Freeze scheduled in less than 30 minutes - delaying deployment');
    // Implement delay or alternative strategy
  }
}

Better Team Communication

Automatically inform your team about upcoming freezes:

#!/bin/bash
# Daily freeze check script

RESPONSE=$(curl -s "https://www.mergefreeze.com/api/branches/myorg/myrepo/main?access_token=$TOKEN")
NEXT_FREEZE=$(echo $RESPONSE | jq -r '.next_freeze_at')

if [ "$NEXT_FREEZE" != "null" ]; then
  FREEZE_TIME=$(date -d "@$NEXT_FREEZE" '+%Y-%m-%d %H:%M:%S')
  echo "🚨 Upcoming freeze: $FREEZE_TIME"
  
  # Send to Slack, email, or other notification system
  curl -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"Upcoming freeze for myrepo/main: $FREEZE_TIME\"}" \
    $SLACK_WEBHOOK_URL
fi

Integration with Monitoring Tools

Connect freeze schedules with your monitoring and alerting systems:

import requests
from datetime import datetime, timedelta

def check_freeze_schedule(org, repo, branch, token):
    """Check if a freeze is scheduled soon and adjust monitoring accordingly"""
    
    url = f"https://www.mergefreeze.com/api/branches/{org}/{repo}/{branch}"
    params = {"access_token": token}
    
    response = requests.get(url, params=params)
    data = response.json()
    
    if data.get('next_freeze_at'):
        next_freeze = datetime.fromtimestamp(data['next_freeze_at'])
        time_until_freeze = next_freeze - datetime.now()
        
        if time_until_freeze < timedelta(hours=2):
            # Adjust monitoring thresholds before freeze
            print(f"Freeze in {time_until_freeze} - adjusting alert thresholds")
            return {"action": "prepare_for_freeze", "freeze_time": next_freeze}
    
    return {"action": "normal_operations"}

# Use in your monitoring pipeline
schedule_info = check_freeze_schedule("myorg", "myrepo", "main", "your-token")

Real-World Use Cases

Deployment Pipeline Intelligence

# GitHub Actions example
name: Smart Deployment
on: 
  push:
    branches: [main]

jobs:
  check-freeze-schedule:
    runs-on: ubuntu-latest
    outputs:
      should-deploy: ${{ steps.freeze-check.outputs.should-deploy }}
      freeze-time: ${{ steps.freeze-check.outputs.freeze-time }}
    
    steps:
    - name: Check freeze schedule
      id: freeze-check
      run: |
        RESPONSE=$(curl -s "https://www.mergefreeze.com/api/branches/${{ github.repository_owner }}/${{ github.event.repository.name }}/main" \
          -H "Authorization: Bearer ${{ secrets.MERGE_FREEZE_TOKEN }}")
        NEXT_FREEZE=$(echo $RESPONSE | jq -r '.next_freeze_at')
        
        if [ "$NEXT_FREEZE" != "null" ]; then
          CURRENT_TIME=$(date +%s)
          TIME_UNTIL_FREEZE=$((NEXT_FREEZE - CURRENT_TIME))
          
          if [ $TIME_UNTIL_FREEZE -lt 1800 ]; then # 30 minutes
            echo "should-deploy=false" >> $GITHUB_OUTPUT
            echo "freeze-time=$(date -d @$NEXT_FREEZE)" >> $GITHUB_OUTPUT
          else
            echo "should-deploy=true" >> $GITHUB_OUTPUT
          fi
        else
          echo "should-deploy=true" >> $GITHUB_OUTPUT
        fi        

  deploy:
    needs: check-freeze-schedule
    runs-on: ubuntu-latest
    if: needs.check-freeze-schedule.outputs.should-deploy == 'true'
    
    steps:
    - name: Deploy to production
      run: |
        echo "Deploying - no freeze scheduled soon"
        # Your deployment steps here        

Weekend Freeze Awareness

// Check for weekend freezes in your deployment dashboard
async function getWeekendFreezeStatus() {
  const repos = ['frontend', 'api', 'database', 'auth-service'];
  const freezeSchedule = [];
  
  for (const repo of repos) {
    const response = await fetch(`/api/branches/myorg/${repo}/main?access_token=TOKEN`);
    const data = await response.json();
    
    if (data.next_freeze_at) {
      const freezeDate = new Date(data.next_freeze_at * 1000);
      const isWeekend = freezeDate.getDay() === 0 || freezeDate.getDay() === 6;
      
      if (isWeekend) {
        freezeSchedule.push({
          repo: repo,
          freeze_time: freezeDate,
          day: freezeDate.toLocaleDateString('en-US', { weekday: 'long' })
        });
      }
    }
  }
  
  return freezeSchedule;
}

// Display weekend freeze warnings
getWeekendFreezeStatus().then(schedule => {
  if (schedule.length > 0) {
    console.log('đŸ—“ī¸  Weekend freezes scheduled:');
    schedule.forEach(item => {
      console.log(`  ${item.repo}: ${item.day} at ${item.freeze_time.toLocaleTimeString()}`);
    });
  }
});

Maintenance Window Coordination

# Coordinate maintenance windows across multiple services
#!/bin/bash

SERVICES=("web-app" "api-gateway" "user-service" "payment-processor")
MAINTENANCE_START=$(date -d "today 2 AM" +%s)
MAINTENANCE_END=$(date -d "today 6 AM" +%s)

echo "Checking freeze schedules for maintenance window..."
echo "Maintenance: $(date -d @$MAINTENANCE_START) to $(date -d @$MAINTENANCE_END)"
echo ""

for SERVICE in "${SERVICES[@]}"; do
  RESPONSE=$(curl -s "https://www.mergefreeze.com/api/branches/myorg/$SERVICE/main?access_token=$TOKEN")
  NEXT_FREEZE=$(echo $RESPONSE | jq -r '.next_freeze_at')
  NEXT_UNFREEZE=$(echo $RESPONSE | jq -r '.next_unfreeze_at')
  
  echo "đŸ“Ļ $SERVICE:"
  
  if [ "$NEXT_FREEZE" != "null" ]; then
    if [ $NEXT_FREEZE -le $MAINTENANCE_END ] && [ $NEXT_FREEZE -ge $MAINTENANCE_START ]; then
      echo "  ✅ Freeze aligns with maintenance window"
    else
      echo "  âš ī¸  Freeze scheduled outside maintenance window: $(date -d @$NEXT_FREEZE)"
    fi
  else
    echo "  â„šī¸  No freeze scheduled"
  fi
done

Advanced Integration Patterns

Database-Driven Freeze Tracking

-- Store freeze schedules in your database for complex queries
CREATE TABLE freeze_schedules (
  id SERIAL PRIMARY KEY,
  organization VARCHAR(100) NOT NULL,
  repository VARCHAR(100) NOT NULL,
  branch VARCHAR(100) NOT NULL,
  next_freeze_at TIMESTAMP,
  next_unfreeze_at TIMESTAMP,
  last_updated TIMESTAMP DEFAULT NOW()
);

-- Sample query to find all repos with freezes this weekend
SELECT organization, repository, branch, next_freeze_at
FROM freeze_schedules 
WHERE EXTRACT(DOW FROM next_freeze_at) IN (0, 6)  -- Sunday or Saturday
  AND next_freeze_at > NOW()
  AND next_freeze_at < NOW() + INTERVAL '7 days';

Slack Bot Integration

// Slack bot that reports upcoming freezes
app.command('/freeze-schedule', async ({ command, ack, respond }) => {
  await ack();
  
  const repos = command.text ? [command.text] : await getDefaultRepos();
  const schedules = [];
  
  for (const repo of repos) {
    const response = await fetch(`https://www.mergefreeze.com/api/branches/myorg/${repo}/main?access_token=${process.env.MERGE_FREEZE_TOKEN}`);
    const data = await response.json();
    
    if (data.next_freeze_at) {
      schedules.push({
        repo: repo,
        freeze_time: new Date(data.next_freeze_at * 1000),
        unfreeze_time: data.next_unfreeze_at ? new Date(data.next_unfreeze_at * 1000) : null
      });
    }
  }
  
  if (schedules.length === 0) {
    await respond('🎉 No freezes scheduled for the specified repositories!');
  } else {
    const message = schedules.map(s => 
      `🧊 *${s.repo}*: Freeze at ${s.freeze_time.toLocaleString()}` +
      (s.unfreeze_time ? ` → Unfreeze at ${s.unfreeze_time.toLocaleString()}` : '')
    ).join('\n');
    
    await respond(`📅 *Upcoming Freeze Schedule:*\n${message}`);
  }
});

Migration and Compatibility

Backward Compatibility

  • Existing integrations continue to work - these are additional fields
  • Null handling - fields return null when no freeze is scheduled
  • Epoch format - Standard Unix timestamps for easy conversion

Testing Your Integration

# Test with a repository that has scheduled freezes
curl "https://www.mergefreeze.com/api/branches/your-org/your-repo/main?access_token=YOUR_TOKEN" | jq '.'

# Expected output:
{
  "frozen": false,
  "next_freeze_at": 1666310400,
  "next_unfreeze_at": 1666324800,
  // ... other fields
}

Best Practices

1. Handle Null Values

Always check if timestamps exist before using them:

if (data.next_freeze_at !== null) {
  const nextFreeze = new Date(data.next_freeze_at * 1000);
  // Process freeze time
}

2. Cache Responsibly

Schedule data doesn’t change frequently, so caching is appropriate:

// Cache for 5 minutes
const CACHE_TTL = 5 * 60 * 1000;

3. Time Zone Awareness

Convert epoch timestamps to appropriate time zones:

const localTime = new Date(epochTimestamp * 1000).toLocaleString('en-US', {
  timeZone: 'America/New_York',
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric'
});

Ready to build smarter automation around your freeze schedules?

These timestamp enhancements make it easier than ever to build intelligent deployment workflows that work seamlessly with your freeze schedules.

Your automation can now be truly proactive! 🚀