ملخص سريع
تتيح لك واجهة برمجة تطبيقات Heroku أتمتة عمليات النشر، إدارة التطبيقات، التحكم في الدينو والإضافات والبنية التحتية برمجياً. تعتمد على OAuth 2.0 ومصادقة الرموز، وتوفر نقاط نهاية RESTful للتطبيقات، الدينو، عمليات البناء، خطوط الأنابيب، مع حد معدل 10,000 طلب في الساعة لكل حساب. ستجد هنا خطوات عملية لإعداد المصادقة، استخدام نقاط النهاية الأساسية، تكامل CI/CD، واستراتيجيات النشر للإنتاج.
مقدمة
تشغل Heroku ملايين التطبيقات حول العالم. إذا كنت تبني أتمتة نشر أو خطوط أنابيب CI/CD أو أدوات إدارة تطبيقات متعددة، فإن تكامل Heroku API أمر أساسي. الفرق التي تدير أكثر من 10 تطبيقات Heroku تهدر وقتاً كبيراً في عمليات النشر اليدوية والتعديلات. باستخدام Heroku API يمكنك أتمتة كل شيء: من عمليات النشر وتوسيع الدينو إلى مزامنة التكوينات.
سنتناول في هذا الدليل خطوات تنفيذية لتكامل Heroku API: مصادقة الرموز، إدارة التطبيقات والدينو، خطوط الأنابيب، الإضافات، وحل المشكلات، مع أمثلة عملية وكود جاهز للاستخدام.
💡 Apidog يسهل اختبار تكامل API: اختبر نقاط نهاية Heroku، تحقق من المصادقة، افحص استجابات API واكتشف الأخطاء وصححها—all من مكان واحد. استورد المواصفات، حاكي الاستجابات، وشارك سيناريوهات الاختبار مع فريقك.
ما هي واجهة برمجة تطبيقات Heroku؟
توفر Heroku واجهة منصة RESTful لإدارة التطبيقات والبنية التحتية برمجياً. يمكنك من خلالها:
- إنشاء/تكوين/حذف التطبيقات
- توسيع الدينو وإدارة العمليات
- إدارة عمليات البناء والإصدار
- إدارة الإضافات
- إدارة خطوط الأنابيب
- التحكم في النطاقات وشهادات SSL
- تصريف السجلات والمراقبة
- إدارة الفرق والمتعاونين
الميزات الرئيسية
| الميزة | الوصف |
|---|---|
| تصميم RESTful | طرق HTTP قياسية مع استجابات JSON |
| مصادقة الرمز | Bearer token مع دعم OAuth 2.0 |
| طلبات النطاق | ترقيم الصفحات لمجموعات النتائج الكبيرة |
| تحديد المعدل | 10,000 طلب/ساعة لكل حساب |
| إنشاءات متطابقة | سلوك إعادة محاولة آمن للكتابة |
| ضغط Gzip | ضغط الاستجابة لتقليل النطاق الترددي |
بنية API
الأساس:
https://api.heroku.com/
وتتبع API مواصفات JSON:API بأنماط موارد موحدة.
مقارنة إصدارات API
| الإصدار | الحالة | المصادقة | حالة الاستخدام |
|---|---|---|---|
| Platform API (v3) | الحالي | Bearer Token | جميع عمليات التكامل |
| GitHub Integration | الحالي | OAuth 2.0 | ربط التطبيقات بـ GitHub |
| Container Registry | الحالي | مصادقة Docker | نشر الحاويات |
البدء: إعداد المصادقة
الخطوة 1: إنشاء حساب Heroku
- ادخل إلى موقع Heroku
- اضغط على Sign Up وسجّل حساباً جديداً
- فعّل بريدك الإلكتروني وأكمل الإعدادات
الخطوة 2: تثبيت Heroku CLI
يساعدك CLI في توليد رموز API واختبار الأوامر بسرعة:
# macOS
brew tap heroku/brew && brew install heroku
# Windows
npm install -g heroku
# Linux
curl https://cli-assets.heroku.com/install.sh | sh
الخطوة 3: إنشاء رمز API
سجّل الدخول واحصل على الرمز:
heroku login
# يفتح متصفح للمصادقة
# توليد رمز مؤقت
heroku authorizations:create --short-lived
# رمز طويل الأمد (لـ CI/CD)
heroku authorizations:create --description "CI/CD Pipeline" --expires-in "1 year"
أمان: خزّن الرموز في متغيرات البيئة فقط:
# ملف .env
HEROKU_API_KEY="your_api_key_here"
HEROKU_APP_NAME="your-app-name"
الخطوة 4: مصادقة الرمز
كل طلب API يتطلب هذه الرؤوس:
Authorization: Bearer {api_key}
Accept: application/vnd.heroku+json; version=3
الخطوة 5: اختبار أول استدعاء API
تأكد من صحة المصادقة:
curl -n https://api.heroku.com/account \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY"
استجابة نموذجية:
{
"id": "user-id-here",
"email": "developer@example.com",
"name": "Developer Name",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2026-03-20T14:22:00Z"
}
الخطوة 6: تطبيق المصادقة في الكود
عميل API جاهز لإعادة الاستخدام (Node.js):
const HEROKU_API_KEY = process.env.HEROKU_API_KEY;
const HEROKU_BASE_URL = 'https://api.heroku.com';
const herokuRequest = async (endpoint, options = {}) => {
const response = await fetch(`${HEROKU_BASE_URL}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${HEROKU_API_KEY}`,
'Accept': 'application/vnd.heroku+json; version=3',
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Heroku API Error: ${error.message}`);
}
return response.json();
};
// مثال الاستخدام
const account = await herokuRequest('/account');
console.log(`تم تسجيل الدخول باسم: ${account.email}`);
إدارة التطبيقات
إنشاء تطبيق جديد
const createApp = async (appName, region = 'us') => {
const response = await herokuRequest('/apps', {
method: 'POST',
body: JSON.stringify({
name: appName,
region: region
})
});
return response;
};
// الاستخدام
const app = await createApp('my-awesome-app-2026');
console.log(`تم إنشاء التطبيق: ${app.name}`);
console.log(`عنوان Git: ${app.git_url}`);
console.log(`عنوان الويب: ${app.web_url}`);
نموذج الاستجابة:
{
"id": "app-uuid-here",
"name": "my-awesome-app-2026",
"region": { "name": "us" },
"created_at": "2026-03-25T10:00:00Z",
"updated_at": "2026-03-25T10:00:00Z",
"git_url": "https://git.heroku.com/my-awesome-app-2026.git",
"web_url": "https://my-awesome-app-2026.herokuapp.com",
"owner": { "email": "developer@example.com" },
"build_stack": { "name": "heroku-24" }
}
سرد التطبيقات
const listApps = async (limit = 50) => {
const response = await herokuRequest(`/apps?limit=${limit}`);
return response;
};
const apps = await listApps();
apps.forEach(app => {
console.log(`${app.name} - ${app.web_url}`);
});
تفاصيل التطبيق
const getApp = async (appName) => {
const response = await herokuRequest(`/apps/${appName}`);
return response;
};
const app = await getApp('my-awesome-app-2026');
console.log(`المكدس: ${app.build_stack.name}`);
console.log(`المنطقة: ${app.region.name}`);
تحديث تكوين التطبيق
const updateApp = async (appName, updates) => {
const response = await herokuRequest(`/apps/${appName}`, {
method: 'PATCH',
body: JSON.stringify(updates)
});
return response;
};
// تغيير اسم التطبيق
const updated = await updateApp('old-app-name', { name: 'new-app-name' });
حذف تطبيق
const deleteApp = async (appName) => {
await herokuRequest(`/apps/${appName}`, {
method: 'DELETE'
});
console.log(`تم حذف التطبيق ${appName} بنجاح`);
};
إدارة الدينو
توسيع نطاق الدينو
const scaleDyno = async (appName, processType, quantity) => {
const response = await herokuRequest(`/apps/${appName}/formation/${processType}`, {
method: 'PATCH',
body: JSON.stringify({ quantity: quantity })
});
return response;
};
// توسيع web dyno إلى 3
const formation = await scaleDyno('my-app', 'web', 3);
console.log(`تم التوسيع إلى ${formation.quantity} من ${processType} دينو`);
عرض تكوين الدينو
const getFormation = async (appName, processType = null) => {
const endpoint = processType
? `/apps/${appName}/formation/${processType}`
: `/apps/${appName}/formation`;
const response = await herokuRequest(endpoint);
return response;
};
const formation = await getFormation('my-app');
formation.forEach(proc => {
console.log(`${proc.type}: ${proc.quantity} دينو (@ ${proc.size})`);
});
أحجام الدينو المتاحة
| نوع الدينو | حالة الاستخدام | التكلفة/شهر |
|---|---|---|
| eco | مشاريع الهواة | $5 |
| basic | تطبيقات إنتاج صغيرة | $7 |
| standard-1x | أعباء العمل القياسية | $25 |
| standard-2x | تطبيقات عالية الأداء | $50 |
| performance | تطبيقات حيوية للإنتاج | $250+ |
| private | عزل الشركات | مخصص |
إعادة تشغيل الدينو
const restartDynos = async (appName, processType = null) => {
const endpoint = processType
? `/apps/${appName}/formation/${processType}`
: `/apps/${appName}/dynos`;
await herokuRequest(endpoint, { method: 'DELETE' });
console.log(`تمت إعادة تشغيل الدينو لتطبيق ${appName}`);
};
تشغيل دينو لمرة واحدة
const runCommand = async (appName, command) => {
const response = await herokuRequest(`/apps/${appName}/dynos`, {
method: 'POST',
body: JSON.stringify({
command: command,
size: 'standard-1x'
})
});
return response;
};
const dyno = await runCommand('my-app', 'npm run migrate');
console.log(`بدأ الدينو: ${dyno.id}`);
متغيرات التكوين
جلب متغيرات التكوين
const getConfigVars = async (appName) => {
const response = await herokuRequest(`/apps/${appName}/config-vars`);
return response;
};
const config = await getConfigVars('my-app');
console.log(`DATABASE_URL: ${config.DATABASE_URL}`);
console.log(`NODE_ENV: ${config.NODE_ENV}`);
تعيين متغيرات التكوين
const setConfigVars = async (appName, variables) => {
const response = await herokuRequest(`/apps/${appName}/config-vars`, {
method: 'PATCH',
body: JSON.stringify(variables)
});
return response;
};
const updated = await setConfigVars('my-app', {
NODE_ENV: 'production',
API_SECRET: 'your-secret-key',
LOG_LEVEL: 'info'
});
أفضل الممارسات
- لا تخزن الأسرار في الكود—استخدم متغيرات البيئة.
- استخدم تكوينات منفصلة لكل بيئة (تجريبية/إنتاج).
- دوّر الأسرار بشكل منتظم (كل ربع سنة مثلاً).
- قم ببادئة المتغيرات المتعلقة (مثل:
STRIPE_SECRET_KEY).
إدارة البناء والإصدار
إنشاء بناء
const createBuild = async (appName, sourceBlobUrl) => {
const response = await herokuRequest(`/apps/${appName}/builds`, {
method: 'POST',
body: JSON.stringify({
source_blob: { url: sourceBlobUrl }
})
});
return response;
};
const build = await createBuild('my-app', 'https://storage.example.com/source.tar.gz');
console.log(`بدأ البناء: ${build.id}`);
console.log(`الحالة: ${build.status}`);
حالة البناء
const getBuild = async (appName, buildId) => {
const response = await herokuRequest(`/apps/${appName}/builds/${buildId}`);
return response;
};
const checkBuildStatus = async (appName, buildId, maxAttempts = 30) => {
for (let i = 0; i < maxAttempts; i++) {
const build = await getBuild(appName, buildId);
if (build.status === 'succeeded') {
console.log('تم البناء بنجاح!');
return build;
} else if (build.status === 'failed') {
throw new Error(`فشل البناء: ${build.output}`);
}
console.log(`البناء قيد التقدم... المحاولة ${i + 1}`);
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error('انتهت مهلة البناء');
};
سجل الإصدارات
const listReleases = async (appName, limit = 10) => {
const response = await herokuRequest(`/apps/${appName}/releases?limit=${limit}`);
return response;
};
const releases = await listReleases('my-app');
releases.forEach(release => {
console.log(`الإصدار v${release.version} - ${release.description} - ${release.created_at}`);
});
العودة إلى إصدار سابق
const rollback = async (appName, releaseId) => {
const response = await herokuRequest(`/apps/${appName}/releases`, {
method: 'POST',
body: JSON.stringify({ rollback: releaseId })
});
return response;
};
const rollbackRelease = await rollback('my-app', 42);
console.log(`تمت العودة إلى الإصدار v${rollbackRelease.version}`);
إدارة خطوط الأنابيب
إنشاء خط أنابيب
const createPipeline = async (pipelineName) => {
const response = await herokuRequest('/pipelines', {
method: 'POST',
body: JSON.stringify({ name: pipelineName })
});
return response;
};
const pipeline = await createPipeline('my-app-pipeline');
console.log(`تم إنشاء خط الأنابيب: ${pipeline.id}`);
إضافة تطبيق لخط الأنابيب
const addAppToPipeline = async (pipelineId, appName, stage) => {
const response = await herokuRequest('/pipeline-couplings', {
method: 'POST',
body: JSON.stringify({
pipeline: pipelineId,
app: appName,
stage: stage // 'development', 'staging', 'production'
})
});
return response;
};
// أمثلة ربط التطبيقات بالمراحل
await addAppToPipeline(pipelineId, 'my-app-dev', 'development');
await addAppToPipeline(pipelineId, 'my-app-staging', 'staging');
await addAppToPipeline(pipelineId, 'my-app-prod', 'production');
ترقية السلاغ بين المراحل
const promoteSlug = async (slugId, toApp) => {
await herokuRequest('/promotions', {
method: 'POST',
body: JSON.stringify({
from: toApp, // تطبيق المصدر
to: toApp, // التطبيق الهدف
slug: slugId
})
});
console.log(`تمت ترقية السلاغ ${slugId} إلى ${toApp}`);
};
إدارة الإضافات
توفير إضافة (Addon)
const provisionAddon = async (appName, addonPlan, config = {}) => {
const response = await herokuRequest('/addon-attachments', {
method: 'POST',
body: JSON.stringify({
app: appName,
plan: addonPlan,
config: config
})
});
return response;
};
// توفير PostgreSQL
const db = await provisionAddon('my-app', 'heroku-postgresql:mini', {});
console.log(`تم توفير قاعدة البيانات: ${db.addon.name}`);
console.log(`DATABASE_URL: ${db.addon.config_vars.DATABASE_URL}`);
الإضافات الشائعة
| الإضافة | الخطة | السعر المبدئي | الاستخدام |
|---|---|---|---|
| heroku-postgresql | mini | $5/شهر | قاعدة بيانات |
| heroku-redis | mini | $5/شهر | التخزين المؤقت |
| papertrail | choklad | $7/شهر | تجميع السجلات |
| sentry | developer | مجاني | تتبع الأخطاء |
| mailgun | sandbox | مجاني | إرسال الإيميلات |
| newrelic | lite | مجاني | مراقبة التطبيق |
سرد الإضافات
const listAddons = async (appName) => {
const response = await herokuRequest(`/apps/${appName}/addons`);
return response;
};
const addons = await listAddons('my-app');
addons.forEach(addon => {
console.log(`${addon.plan.name} - $${addon.pricing.plan.price} - ${addon.state}`);
});
إزالة إضافة
const removeAddon = async (appName, addonId) => {
await herokuRequest(`/apps/${appName}/addons/${addonId}`, {
method: 'DELETE'
});
console.log(`تمت إزالة الإضافة ${addonId} من ${appName}`);
};
إدارة النطاقات وشهادات SSL
إضافة نطاق مخصص
const addDomain = async (appName, domainName) => {
const response = await herokuRequest(`/apps/${appName}/domains`, {
method: 'POST',
body: JSON.stringify({ hostname: domainName })
});
return response;
};
const domain = await addDomain('my-app', 'api.example.com');
console.log(`هدف CNAME: ${domain.cname}`);
تكوين شهادات SSL مخصصة
const addSslCertificate = async (appName, domainId, certificateChain, privateKey) => {
const response = await herokuRequest(`/apps/${appName}/domains/${domainId}/ssl_endpoint`, {
method: 'PATCH',
body: JSON.stringify({
ssl_cert: {
cert_chain: certificateChain,
private_key: privateKey
}
})
});
return response;
};
SSL تلقائي باستخدام ACM
const enableACM = async (appName, domainName) => {
const response = await herokuRequest(`/apps/${appName}/domains/${domainName}/sni_endpoint`, {
method: 'POST',
body: JSON.stringify({ kind: 'acm' })
});
return response;
};
تحديد المعدل والحصص
حدود المعدل
- الحد القياسي: 10,000 طلب/ساعة لكل حساب
- نافذة متجددة: 60 دقيقة
- إعادة الضبط تلقائية
استجابات HTTP 429 تعني تجاوز الحد.
تطبيق معالجة حدود المعدل (Rate Limit)
const makeRateLimitedRequest = async (endpoint, options = {}, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await herokuRequest(endpoint, options);
const remaining = response.headers.get('RateLimit-Remaining');
const resetTime = response.headers.get('RateLimit-Reset');
if (remaining < 100) {
console.warn(`الحد المتبقي المنخفض: ${remaining}، يتم إعادة تعيينه في ${resetTime}`);
}
return response;
} catch (error) {
if (error.message.includes('429') && attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`تم تجاوز الحد. إعادة المحاولة خلال ${delay} مللي ثانية...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
};
رؤوس حدود المعدل
| الرأس | الوصف |
|---|---|
RateLimit-Limit |
الحد الأقصى للطلبات في الساعة |
RateLimit-Remaining |
الطلبات المتبقية في النافذة |
RateLimit-Reset |
طابع زمني Unix لإعادة التعيين |
استكشاف الأخطاء الشائعة وإصلاحها
فشل المصادقة (401)
- تحقق من صحة رمز API:
heroku authorizations - تأكد من أن الرمز لم ينتهِ
- افحص متغير البيئة لفراغات زائدة
- أنشئ رمزاً جديداً إذا لزم الأمر
اسم التطبيق محجوز
- استخدم أسماء فريدة (مثلاً UUID أو لاحقة عشوائية)
- أمثلة:
const generateUniqueAppName = (baseName) => {
const timestamp = Date.now().toString(36);
const random = Math.random().toString(36).substring(2, 6);
return `${baseName}-${timestamp}-${random}`;
};
فشل تكوين الدينو
- تأكد من وجود نوع العملية في Procfile
- تحقق من حصة الدينو
- راجع حالة التطبيق واستخدام ساعات الدينو:
heroku ps --app=my-app
فشل البناء بانتهاء المهلة
- حسن اختيار حزمة البناء
- استخدم التخزين المؤقت للتبعيات
- قسم البناءات الكبيرة
- استخدم سلاغ مبنية مسبقاً
تجاوز حد المعدل
- طبّق قائمة انتظار للطلبات
- استخدم التراجع الأسي عند الخطأ 429
- راقب رؤوس المعدل
- مثال محدد معدل:
class HerokuRateLimiter {
constructor(requestsPerMinute = 150) {
this.queue = [];
this.interval = 60000 / requestsPerMinute;
this.processing = false;
}
async add(requestFn) {
return new Promise((resolve, reject) => {
this.queue.push({ requestFn, resolve, reject });
this.process();
});
}
async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
while (this.queue.length > 0) {
const { requestFn, resolve, reject } = this.queue.shift();
try {
const result = await requestFn();
resolve(result);
} catch (error) {
reject(error);
}
if (this.queue.length > 0) {
await new Promise(r => setTimeout(r, this.interval));
}
}
this.processing = false;
}
}
قائمة التحقق لنشر الإنتاج
- [ ] استخدم رموز API طويلة الأمد لـ CI/CD
- [ ] خزّن الرموز باستخدام حلول أسرار آمنة (Vault, AWS Secrets Manager)
- [ ] طبّق تحديد المعدل وقوائم انتظار الطلبات
- [ ] أضف معالجة أخطاء شاملة
- [ ] سجل جميع استدعاءات API
- [ ] راقب استخدام ساعات الدينو
- [ ] فعّل تصريف السجلات
- [ ] أتمت ترقية خطوط الأنابيب
- [ ] فعّل إدارة الشهادات التلقائية
- [ ] أنشئ استراتيجية نسخ احتياطي لقواعد البيانات
المراقبة والتنبيه
راقب المقاييس التالية:
const metrics = {
apiCalls: { total: 0, successful: 0, failed: 0, rateLimited: 0 },
dynoHours: { used: 0, quota: 1000 },
deployments: { successful: 0, failed: 0, avg_duration: 0 }
};
const failureRate = metrics.apiCalls.failed / metrics.apiCalls.total;
if (failureRate > 0.05) {
sendAlert('معدل فشل Heroku API أعلى من 5%');
}
if (metrics.dynoHours.used > metrics.dynoHours.quota * 0.8) {
sendAlert('استخدام ساعات الدينو أعلى من 80%');
}
حالات الاستخدام الواقعية
خط أنابيب CI/CD مؤتمت
- التحدي: النشر اليدوي يسبب أخطاء وتأخير
- الحل: GitHub Actions + Heroku API
- النتيجة: نشر أسرع بنسبة 90%
التنفيذ:
- دفع GitHub يشغل سير العمل
- تشغيل الاختبارات
- Heroku API ينشئ بناء تلقائي
- ترقية التطبيق من التجريبي للإنتاج
- إبلاغ الفريق عند النجاح/الفشل
إدارة بيئات متعددة
- التحدي: مزامنة التكوين اليدوية عبر بيئات متعددة
- الحل: إدارة التكوين مركزياً عبر Heroku API
- النتيجة: توفير وقت وتحقيق اتساق في التكوينات
تطبيق عملي:
- مزامنة متغيرات التكوين عبر البيئات
- توفير الإضافات تلقائياً
- عمليات مجمعة لعملاء جدد
التوسيع التلقائي حسب الحمل
- التحدي: التوسيع اليدوي خلال ذروات المبيعات
- الحل: توسيع تلقائي معتمد على Heroku API
- النتيجة: عدم توقف الخدمة خلال الذروات
منطق التنفيذ:
- راقب أوقات الاستجابة
- وسع الدينو تلقائياً عند الحاجة
- قلل خلال انخفاض الحمل
- نبه الفريق عند الاستخدام العالي
الخلاصة
Heroku API يمنحك تحكم كامل ومرن في البنية التحتية والنشر. لتكامل ناجح:
- خزّن الرموز بأمان ودوّرها بانتظام
- راقب حدود المعدل وفعّل التراجع الأسي
- اعتمد خطوط الأنابيب لأتمتة CI/CD
- أضف معالجة أخطاء قوية في كل خطوة
- استخدم Apidog لاختبار وتوثيق نقاط النهاية ومشاركة السيناريوهات
قسم الأسئلة الشائعة
ما هو استخدام واجهة برمجة تطبيقات Heroku؟
تُستخدم لإدارة التطبيقات، الدينو، الإضافات، والبنية التحتية برمجياً. من أهم الاستخدامات أتمتة CI/CD وأدوات الإدارة وأنظمة التوسيع ولوحات المراقبة.
كيف أحصل على مفتاح API لـ Heroku؟
ثبت Heroku CLI، نفذ heroku login ثم أنشئ ترخيصاً بـ heroku authorizations:create. خزّن الرمز في متغيرات البيئة.
هل واجهة برمجة تطبيقات Heroku مجانية للاستخدام؟
الواجهة مجانية، لكن تدفع مقابل الموارد (دينوهات، إضافات...). حد المعدل 10,000 طلب بالساعة لكل حساب.
ما هي طريقة المصادقة المستخدمة؟
مصادقة Bearer token. أضف رأس
Authorization: Bearer {api_key}
لكل طلب. الرموز قد تكون قصيرة أو طويلة الأمد.
كيف أتعامل مع حدود معدل Heroku API؟
راقب رأس RateLimit-Remaining، استخدم قائمة انتظار للطلبات، وطبّق تراجع أسي عند ظهور 429.
هل يمكنني النشر بدون Git؟
نعم، استخدم Builds API مع عنوان URL لكائن مصدر (source blob) من تخزين سحابي (S3، GCS...).
كيف أؤتمت عمليات النشر؟
استخدم Pipeline API: أنشئ عمليات بناء، رقي السلاغات عبر المراحل، وادمج مع GitHub أو أي CI.
ما الفرق بين الإصدار (Release) والبناء (Build)؟
Build يحوّل الكود إلى سلاغ. Release يدمج السلاغ مع التكوين ويجعل التطبيق قابلاً للنشر.
كيف أعود لإصدار سابق بعد نشر فاشل؟
استخدم Releases API، أرسل POST إلى /releases مع rollback: <release_id>. سيُنشر الإصدار السابق.
هل يمكنني إدارة حسابات Heroku متعددة؟
نعم، استخدم رموز API منفصلة لكل حساب وبدّل عبر متغير البيئة HEROKU_API_KEY.

Top comments (0)