548 lines
14 KiB
Markdown
548 lines
14 KiB
Markdown
# Pack Registry CI/CD Integration
|
|
|
|
This document provides examples and best practices for integrating pack publishing with CI/CD pipelines.
|
|
|
|
## Overview
|
|
|
|
Automating pack registry publishing ensures:
|
|
- Consistent pack versioning and releases
|
|
- Automated checksum generation
|
|
- Registry index updates on every release
|
|
- Quality assurance through automated testing
|
|
|
|
## Prerequisites
|
|
|
|
1. **Pack Structure**: Your pack must have a valid `pack.yaml`
|
|
2. **Registry Index**: A git repository hosting your `index.json`
|
|
3. **Pack Storage**: A place to host pack archives (GitHub Releases, S3, etc.)
|
|
4. **Attune CLI**: Available in CI environment
|
|
|
|
## GitHub Actions Examples
|
|
|
|
### Example 1: Publish Pack on Git Tag
|
|
|
|
```yaml
|
|
# .github/workflows/publish-pack.yml
|
|
name: Publish Pack
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*.*.*'
|
|
|
|
jobs:
|
|
publish:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout pack repository
|
|
uses: actions/checkout@v3
|
|
|
|
- name: Install Attune CLI
|
|
run: |
|
|
curl -L https://github.com/attune/attune/releases/latest/download/attune-cli-linux -o /usr/local/bin/attune
|
|
chmod +x /usr/local/bin/attune
|
|
|
|
- name: Validate pack.yaml
|
|
run: |
|
|
if [ ! -f "pack.yaml" ]; then
|
|
echo "Error: pack.yaml not found"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Run pack tests
|
|
run: attune pack test . --detailed
|
|
|
|
- name: Generate checksum
|
|
id: checksum
|
|
run: |
|
|
CHECKSUM=$(attune pack checksum . --json | jq -r '.checksum')
|
|
echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT
|
|
|
|
- name: Create GitHub Release
|
|
id: create_release
|
|
uses: actions/create-release@v1
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
with:
|
|
tag_name: ${{ github.ref }}
|
|
release_name: Release ${{ github.ref }}
|
|
draft: false
|
|
prerelease: false
|
|
|
|
- name: Create pack archive
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/v}
|
|
tar -czf pack-${VERSION}.tar.gz --exclude='.git' .
|
|
|
|
- name: Upload pack archive
|
|
uses: actions/upload-release-asset@v1
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
with:
|
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
asset_path: ./pack-${{ steps.version.outputs.version }}.tar.gz
|
|
asset_name: pack-${{ steps.version.outputs.version }}.tar.gz
|
|
asset_content_type: application/gzip
|
|
|
|
- name: Generate index entry
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/v}
|
|
attune pack index-entry . \
|
|
--git-url "https://github.com/${{ github.repository }}" \
|
|
--git-ref "${{ github.ref_name }}" \
|
|
--archive-url "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/pack-${VERSION}.tar.gz" \
|
|
--format json > index-entry.json
|
|
|
|
- name: Checkout registry repository
|
|
uses: actions/checkout@v3
|
|
with:
|
|
repository: your-org/attune-registry
|
|
token: ${{ secrets.REGISTRY_TOKEN }}
|
|
path: registry
|
|
|
|
- name: Update registry index
|
|
run: |
|
|
attune pack index-update \
|
|
--index registry/index.json \
|
|
. \
|
|
--git-url "https://github.com/${{ github.repository }}" \
|
|
--git-ref "${{ github.ref_name }}" \
|
|
--archive-url "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/pack-${VERSION}.tar.gz" \
|
|
--update
|
|
|
|
- name: Commit and push registry changes
|
|
working-directory: registry
|
|
run: |
|
|
git config user.name "GitHub Actions"
|
|
git config user.email "actions@github.com"
|
|
git add index.json
|
|
git commit -m "Add/update pack: $(yq -r '.ref' ../pack.yaml) ${{ github.ref_name }}"
|
|
git push
|
|
```
|
|
|
|
### Example 2: Multi-Pack Repository
|
|
|
|
```yaml
|
|
# .github/workflows/publish-packs.yml
|
|
name: Publish All Packs
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
paths:
|
|
- 'packs/**'
|
|
|
|
jobs:
|
|
detect-changed-packs:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
packs: ${{ steps.changed.outputs.packs }}
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
with:
|
|
fetch-depth: 2
|
|
|
|
- name: Detect changed packs
|
|
id: changed
|
|
run: |
|
|
CHANGED_PACKS=$(git diff --name-only HEAD^ HEAD | grep '^packs/' | cut -d'/' -f2 | sort -u | jq -R -s -c 'split("\n")[:-1]')
|
|
echo "packs=$CHANGED_PACKS" >> $GITHUB_OUTPUT
|
|
|
|
publish-pack:
|
|
needs: detect-changed-packs
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
matrix:
|
|
pack: ${{ fromJson(needs.detect-changed-packs.outputs.packs) }}
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
|
|
- name: Install Attune CLI
|
|
run: |
|
|
curl -L https://github.com/attune/attune/releases/latest/download/attune-cli-linux -o /usr/local/bin/attune
|
|
chmod +x /usr/local/bin/attune
|
|
|
|
- name: Test pack
|
|
run: attune pack test packs/${{ matrix.pack }}
|
|
|
|
- name: Update registry
|
|
run: |
|
|
# Clone registry
|
|
git clone https://${{ secrets.REGISTRY_TOKEN }}@github.com/your-org/attune-registry.git registry
|
|
|
|
# Update index
|
|
attune pack index-update \
|
|
--index registry/index.json \
|
|
packs/${{ matrix.pack }} \
|
|
--git-url "https://github.com/${{ github.repository }}" \
|
|
--git-ref "main" \
|
|
--update
|
|
|
|
# Commit changes
|
|
cd registry
|
|
git config user.name "GitHub Actions"
|
|
git config user.email "actions@github.com"
|
|
git add index.json
|
|
git commit -m "Update pack: ${{ matrix.pack }}" || exit 0
|
|
git push
|
|
```
|
|
|
|
### Example 3: Registry Maintenance
|
|
|
|
```yaml
|
|
# .github/workflows/maintain-registry.yml
|
|
name: Maintain Registry
|
|
|
|
on:
|
|
schedule:
|
|
# Run weekly on Sundays at midnight
|
|
- cron: '0 0 * * 0'
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
merge-registries:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Install Attune CLI
|
|
run: |
|
|
curl -L https://github.com/attune/attune/releases/latest/download/attune-cli-linux -o /usr/local/bin/attune
|
|
chmod +x /usr/local/bin/attune
|
|
|
|
- name: Download registries
|
|
run: |
|
|
mkdir registries
|
|
curl -o registries/main.json https://registry.attune.io/index.json
|
|
curl -o registries/community.json https://community.attune.io/index.json
|
|
|
|
- name: Merge registries
|
|
run: |
|
|
attune pack index-merge \
|
|
--output merged-index.json \
|
|
registries/*.json
|
|
|
|
- name: Upload merged index
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: merged-registry
|
|
path: merged-index.json
|
|
```
|
|
|
|
## GitLab CI Examples
|
|
|
|
### Example 1: Publish on Tag
|
|
|
|
```yaml
|
|
# .gitlab-ci.yml
|
|
stages:
|
|
- test
|
|
- publish
|
|
|
|
variables:
|
|
PACK_VERSION: ${CI_COMMIT_TAG#v}
|
|
|
|
test:pack:
|
|
stage: test
|
|
image: attune/cli:latest
|
|
script:
|
|
- attune pack test .
|
|
only:
|
|
- tags
|
|
|
|
publish:pack:
|
|
stage: publish
|
|
image: attune/cli:latest
|
|
script:
|
|
# Generate checksum
|
|
- CHECKSUM=$(attune pack checksum . --json | jq -r '.checksum')
|
|
|
|
# Create archive
|
|
- tar -czf pack-${PACK_VERSION}.tar.gz --exclude='.git' .
|
|
|
|
# Upload to package registry
|
|
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file pack-${PACK_VERSION}.tar.gz "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pack/${PACK_VERSION}/pack-${PACK_VERSION}.tar.gz"'
|
|
|
|
# Clone registry
|
|
- git clone https://oauth2:${REGISTRY_TOKEN}@gitlab.com/your-org/attune-registry.git registry
|
|
|
|
# Update index
|
|
- |
|
|
attune pack index-update \
|
|
--index registry/index.json \
|
|
. \
|
|
--git-url "${CI_PROJECT_URL}" \
|
|
--git-ref "${CI_COMMIT_TAG}" \
|
|
--archive-url "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/pack/${PACK_VERSION}/pack-${PACK_VERSION}.tar.gz" \
|
|
--update
|
|
|
|
# Commit and push
|
|
- cd registry
|
|
- git config user.name "GitLab CI"
|
|
- git config user.email "ci@gitlab.com"
|
|
- git add index.json
|
|
- git commit -m "Update pack from ${CI_PROJECT_NAME} ${CI_COMMIT_TAG}"
|
|
- git push
|
|
only:
|
|
- tags
|
|
```
|
|
|
|
## Jenkins Pipeline Example
|
|
|
|
```groovy
|
|
// Jenkinsfile
|
|
pipeline {
|
|
agent any
|
|
|
|
environment {
|
|
PACK_VERSION = sh(script: "yq -r '.version' pack.yaml", returnStdout: true).trim()
|
|
PACK_REF = sh(script: "yq -r '.ref' pack.yaml", returnStdout: true).trim()
|
|
}
|
|
|
|
stages {
|
|
stage('Test') {
|
|
steps {
|
|
sh 'attune pack test .'
|
|
}
|
|
}
|
|
|
|
stage('Build') {
|
|
when {
|
|
tag pattern: "v.*", comparator: "REGEXP"
|
|
}
|
|
steps {
|
|
sh "tar -czf pack-${PACK_VERSION}.tar.gz --exclude='.git' ."
|
|
archiveArtifacts artifacts: "pack-${PACK_VERSION}.tar.gz"
|
|
}
|
|
}
|
|
|
|
stage('Publish') {
|
|
when {
|
|
tag pattern: "v.*", comparator: "REGEXP"
|
|
}
|
|
steps {
|
|
script {
|
|
// Upload to artifact repository
|
|
sh """
|
|
curl -u ${ARTIFACTORY_CREDS} \
|
|
-T pack-${PACK_VERSION}.tar.gz \
|
|
"https://artifactory.example.com/packs/${PACK_REF}/${PACK_VERSION}/"
|
|
"""
|
|
|
|
// Update registry
|
|
sh """
|
|
git clone https://${REGISTRY_CREDS}@github.com/your-org/attune-registry.git registry
|
|
|
|
attune pack index-update \
|
|
--index registry/index.json \
|
|
. \
|
|
--git-url "${GIT_URL}" \
|
|
--git-ref "${TAG_NAME}" \
|
|
--archive-url "https://artifactory.example.com/packs/${PACK_REF}/${PACK_VERSION}/pack-${PACK_VERSION}.tar.gz" \
|
|
--update
|
|
|
|
cd registry
|
|
git config user.name "Jenkins"
|
|
git config user.email "jenkins@example.com"
|
|
git add index.json
|
|
git commit -m "Update ${PACK_REF} to ${PACK_VERSION}"
|
|
git push
|
|
"""
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Versioning Strategy
|
|
|
|
Use semantic versioning for packs:
|
|
- **Major**: Breaking changes to actions/sensors
|
|
- **Minor**: New features, backward compatible
|
|
- **Patch**: Bug fixes
|
|
|
|
```yaml
|
|
# pack.yaml
|
|
version: "2.1.3"
|
|
```
|
|
|
|
### 2. Automated Testing
|
|
|
|
Always run pack tests before publishing:
|
|
|
|
```bash
|
|
# In CI pipeline
|
|
attune pack test . --detailed || exit 1
|
|
```
|
|
|
|
### 3. Checksum Verification
|
|
|
|
Always generate and include checksums:
|
|
|
|
```bash
|
|
CHECKSUM=$(attune pack checksum . --json | jq -r '.checksum')
|
|
```
|
|
|
|
### 4. Registry Security
|
|
|
|
- Use separate tokens for registry access
|
|
- Never commit tokens to source control
|
|
- Use CI/CD secrets management
|
|
- Rotate tokens regularly
|
|
|
|
### 5. Archive Hosting
|
|
|
|
Options for hosting pack archives:
|
|
- **GitHub Releases**: Free, integrated with source
|
|
- **GitLab Package Registry**: Built-in package management
|
|
- **Artifactory/Nexus**: Enterprise artifact management
|
|
- **S3/Cloud Storage**: Scalable, CDN-friendly
|
|
|
|
### 6. Registry Structure
|
|
|
|
Maintain a separate git repository for your registry:
|
|
|
|
```
|
|
attune-registry/
|
|
├── index.json # Main registry index
|
|
├── README.md # Usage instructions
|
|
├── .github/
|
|
│ └── workflows/
|
|
│ └── validate.yml # Index validation
|
|
└── scripts/
|
|
└── validate.sh # Validation script
|
|
```
|
|
|
|
### 7. Index Validation
|
|
|
|
Add validation to registry repository:
|
|
|
|
```yaml
|
|
# .github/workflows/validate.yml
|
|
name: Validate Index
|
|
|
|
on: [pull_request, push]
|
|
|
|
jobs:
|
|
validate:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
- name: Validate JSON
|
|
run: |
|
|
jq empty index.json || exit 1
|
|
- name: Check schema
|
|
run: |
|
|
# Ensure required fields exist
|
|
jq -e '.packs | length > 0' index.json
|
|
jq -e '.packs[] | .ref, .version, .install_sources' index.json
|
|
```
|
|
|
|
## Manual Publishing Workflow
|
|
|
|
For manual/local publishing:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# publish-pack.sh
|
|
|
|
set -e
|
|
|
|
PACK_DIR="$1"
|
|
REGISTRY_DIR="$2"
|
|
|
|
if [ -z "$PACK_DIR" ] || [ -z "$REGISTRY_DIR" ]; then
|
|
echo "Usage: $0 <pack-dir> <registry-dir>"
|
|
exit 1
|
|
fi
|
|
|
|
cd "$PACK_DIR"
|
|
|
|
# Extract metadata
|
|
PACK_REF=$(yq -r '.ref' pack.yaml)
|
|
VERSION=$(yq -r '.version' pack.yaml)
|
|
|
|
echo "Publishing ${PACK_REF} v${VERSION}..."
|
|
|
|
# Run tests
|
|
echo "Running tests..."
|
|
attune pack test . || exit 1
|
|
|
|
# Calculate checksum
|
|
echo "Calculating checksum..."
|
|
CHECKSUM=$(attune pack checksum . --json | jq -r '.checksum')
|
|
echo "Checksum: $CHECKSUM"
|
|
|
|
# Create archive
|
|
echo "Creating archive..."
|
|
ARCHIVE_NAME="pack-${VERSION}.tar.gz"
|
|
tar -czf "/tmp/${ARCHIVE_NAME}" --exclude='.git' .
|
|
|
|
# Upload archive (customize for your storage)
|
|
echo "Uploading archive..."
|
|
# aws s3 cp "/tmp/${ARCHIVE_NAME}" "s3://my-bucket/packs/${PACK_REF}/${VERSION}/"
|
|
# OR
|
|
# scp "/tmp/${ARCHIVE_NAME}" "server:/path/to/packs/${PACK_REF}/${VERSION}/"
|
|
|
|
# Update registry
|
|
echo "Updating registry index..."
|
|
cd "$REGISTRY_DIR"
|
|
git pull
|
|
|
|
attune pack index-update \
|
|
--index index.json \
|
|
"$PACK_DIR" \
|
|
--git-url "https://github.com/your-org/${PACK_REF}" \
|
|
--git-ref "v${VERSION}" \
|
|
--archive-url "https://storage.example.com/packs/${PACK_REF}/${VERSION}/${ARCHIVE_NAME}" \
|
|
--update
|
|
|
|
# Commit and push
|
|
git add index.json
|
|
git commit -m "Add ${PACK_REF} v${VERSION}"
|
|
git push
|
|
|
|
echo "✓ Successfully published ${PACK_REF} v${VERSION}"
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Issue: Checksum Mismatch
|
|
|
|
```bash
|
|
# Verify checksum locally
|
|
attune pack checksum /path/to/pack --json
|
|
|
|
# Re-generate archive with consistent settings
|
|
tar --sort=name --mtime='@0' --owner=0 --group=0 --numeric-owner \
|
|
-czf pack.tar.gz --exclude='.git' pack/
|
|
```
|
|
|
|
### Issue: Registry Update Fails
|
|
|
|
```bash
|
|
# Validate index.json syntax
|
|
jq empty index.json
|
|
|
|
# Check for duplicate refs
|
|
jq -r '.packs[].ref' index.json | sort | uniq -d
|
|
```
|
|
|
|
### Issue: Pack Tests Fail in CI
|
|
|
|
```bash
|
|
# Run with verbose output
|
|
attune pack test . --detailed --verbose
|
|
|
|
# Check runtime dependencies
|
|
attune pack test . 2>&1 | grep -i "dependency"
|
|
```
|
|
|
|
## See Also
|
|
|
|
- [Pack Registry Documentation](pack-registry.md)
|
|
- [Pack Testing Framework](pack-testing-framework.md)
|
|
- [Pack Install with Testing](pack-install-testing.md)
|
|
- [API Pack Testing](api-pack-testing.md) |