بوابات المطورين مع Backstage
قوالب البرمجيات (المُنشئ)
4 دقيقة للقراءة
قوالب البرمجيات هي الميزة القاتلة لـ Backstage لفرق المنصات. تمكّن المطورين من إنشاء مشاريع جديدة تتبع تلقائياً أفضل ممارسات مؤسستك—هذا حيث تصبح المسارات الذهبية حقيقة.
لماذا قوالب البرمجيات؟
بدون القوالب، كل مشروع جديد يبدأ بشكل مختلف:
بدون القوالب:
المطور أ: "سأعد CI/CD يدوياً..."
المطور ب: "دعني أنسخ من مشروع قديم..."
المطور ج: "ما هي الطريقة القياسية مرة أخرى؟"
النتيجة: مشاريع غير متسقة، ثغرات أمنية، توثيق مفقود
مع القوالب:
جميع المطورين: "انقر → املأ النموذج → احصل على مشروع موحد"
النتيجة: هيكل متسق، أمان مدمج، توثيق متضمن
تشريح القالب
قالب Backstage له ثلاثة أقسام رئيسية:
# هيكل template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: template-name
title: عنوان قابل للقراءة
description: ما ينشئه هذا القالب
tags: [tag1, tag2]
spec:
owner: platform-team
type: service # service, website, library, إلخ
# القسم 1: المعاملات (إدخال المستخدم)
parameters:
- title: عنوان الخطوة 1
properties:
fieldName:
type: string
# القسم 2: الخطوات (الإجراءات للتنفيذ)
steps:
- id: step-id
name: اسم الخطوة
action: action:name
input:
key: value
# القسم 3: المخرجات (ما يظهر للمستخدم)
output:
links:
- title: عنوان الرابط
url: ${{ steps.step-id.output.someUrl }}
مثال قالب كامل
إليك قالب Node.js API جاهز للإنتاج:
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: nodejs-api-template
title: Node.js REST API
description: |
ينشئ Node.js REST API جاهز للإنتاج مع Express،
TypeScript، Docker، بيانات Kubernetes، و CI/CD.
tags:
- nodejs
- typescript
- api
- recommended
spec:
owner: group:platform-team
type: service
parameters:
# الخطوة 1: المعلومات الأساسية
- title: معلومات الخدمة
required:
- name
- description
- owner
properties:
name:
title: اسم الخدمة
type: string
description: اسم فريد لخدمتك
pattern: '^[a-z0-9-]+$'
ui:autofocus: true
ui:help: 'أحرف صغيرة وأرقام وشرطات فقط'
description:
title: الوصف
type: string
description: ماذا تفعل هذه الخدمة؟
owner:
title: المالك
type: string
description: الفريق الذي يملك هذه الخدمة
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
# الخطوة 2: الخيارات التقنية
- title: التكوين التقني
properties:
database:
title: تضمين قاعدة البيانات؟
type: boolean
default: false
databaseType:
title: نوع قاعدة البيانات
type: string
enum:
- postgresql
- mysql
- mongodb
enumNames:
- PostgreSQL (موصى به)
- MySQL
- MongoDB
default: postgresql
ui:widget: select
ui:options:
hidden: '{{ not parameters.database }}'
authentication:
title: طريقة المصادقة
type: string
enum:
- jwt
- oauth2
- none
default: jwt
# الخطوة 3: إعدادات المستودع
- title: تكوين المستودع
required:
- repoUrl
properties:
repoUrl:
title: موقع المستودع
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
allowedOwners:
- acme-corp
steps:
# الخطوة 1: جلب وتشكيل الهيكل
- id: fetch-base
name: جلب القالب الأساسي
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
database: ${{ parameters.database }}
databaseType: ${{ parameters.databaseType }}
authentication: ${{ parameters.authentication }}
# الخطوة 2: إضافة تكوين قاعدة البيانات إذا لزم الأمر
- id: fetch-database
name: إضافة تكوين قاعدة البيانات
if: ${{ parameters.database }}
action: fetch:template
input:
url: ./skeleton-database-${{ parameters.databaseType }}
targetPath: ./src/database
# الخطوة 3: إنشاء مستودع GitHub
- id: publish
name: النشر إلى GitHub
action: publish:github
input:
repoUrl: ${{ parameters.repoUrl }}
description: ${{ parameters.description }}
defaultBranch: main
protectDefaultBranch: true
requireCodeOwnerReviews: true
repoVisibility: internal
# الخطوة 4: إنشاء بيئات GitHub
- id: github-environments
name: إنشاء البيئات
action: github:environment:create
input:
repoUrl: ${{ parameters.repoUrl }}
name: production
deploymentBranchPolicy:
protectedBranches: true
# الخطوة 5: التسجيل في كتالوج Backstage
- id: register
name: التسجيل في الكتالوج
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
# الخطوة 6: تشغيل CI الأولي
- id: trigger-ci
name: تشغيل خط أنابيب CI
action: github:actions:dispatch
input:
repoUrl: ${{ parameters.repoUrl }}
workflowId: ci.yaml
branchOrTagName: main
output:
links:
- title: المستودع
url: ${{ steps.publish.output.remoteUrl }}
- title: فتح في الكتالوج
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}
- title: خط أنابيب CI
url: ${{ steps.publish.output.remoteUrl }}/actions
هيكل الهيكل العظمي للقالب
مجلد ./skeleton يحتوي على ملفات القالب:
skeleton/
├── catalog-info.yaml
├── package.json
├── tsconfig.json
├── Dockerfile
├── .github/
│ └── workflows/
│ ├── ci.yaml
│ └── deploy.yaml
├── kubernetes/
│ ├── deployment.yaml
│ └── service.yaml
├── src/
│ ├── index.ts
│ ├── routes/
│ └── middleware/
└── docs/
└── index.md
مثال ملف هيكل مع القوالب:
# skeleton/catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: ${{ values.name }}
description: ${{ values.description }}
annotations:
github.com/project-slug: acme-corp/${{ values.name }}
backstage.io/techdocs-ref: dir:.
spec:
type: service
lifecycle: experimental
owner: ${{ values.owner }}
الإجراءات المدمجة
يوفر Backstage العديد من الإجراءات المدمجة:
# إجراءات المُنشئ الشائعة
actions:
fetch:
- fetch:template # جلب وعرض القالب
- fetch:plain # جلب بدون عرض
publish:
- publish:github # إنشاء مستودع GitHub
- publish:gitlab # إنشاء مستودع GitLab
- publish:bitbucket # إنشاء مستودع Bitbucket
catalog:
- catalog:register # تسجيل الكيان في الكتالوج
- catalog:write # كتابة catalog-info.yaml
github:
- github:actions:dispatch # تشغيل سير العمل
- github:environment:create # إنشاء البيئة
- github:issues:create # إنشاء مشكلة
debug:
- debug:log # تسجيل القيم للتصحيح
الإجراءات المخصصة
أنشئ إجراءات مخصصة لمؤسستك:
// plugins/scaffolder-backend-module-acme/src/actions/createDatabase.ts
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
export const createDatabaseAction = createTemplateAction({
id: 'acme:database:create',
description: 'ينشئ قاعدة بيانات عبر Crossplane',
schema: {
input: {
type: 'object',
required: ['name', 'engine'],
properties: {
name: { type: 'string' },
engine: { type: 'string', enum: ['postgresql', 'mysql'] },
size: { type: 'string', default: 'small' },
},
},
},
async handler(ctx) {
const { name, engine, size } = ctx.input;
// إنشاء مطالبة Crossplane
await ctx.createKubernetesResource({
apiVersion: 'database.acme.io/v1',
kind: 'DatabaseClaim',
metadata: { name },
spec: { engine, size },
});
ctx.output('databaseName', name);
ctx.output('connectionSecretName', `${name}-connection`);
},
});
في الدرس التالي، سنستكشف TechDocs ونظام الإضافات البيئي. :::