Automate the deployment of Fusion applications to Equinor's Fusion platform using a standardized, secure workflow within GitHub Actions.
This action exists to make it dead simple for Equinor developers to publish their Fusion applications without wrestling with complex CLI commands, authentication setup, or deployment configurations.
The Problem: Publishing Fusion apps traditionally required developers to manually handle authentication tokens, remember CLI syntax, manage environment configurations, and track deployment status across multiple tools.
The Solution: A single GitHub Action that handles all the orchestration behind the scenes while maintaining enterprise security standards.
🔐 Handles Authentication Complexity - Whether you have a pre-acquired token or need Azure Service Principal authentication, it just works
🚀 Eliminates Manual Steps - No more remembering @equinor/fusion-framework-cli commands or debugging deployment issues
🌍 Manages Multi-Environment Deployments - Automatically deploys to the right environment (ci, tr, fprd, fqa, next) with smart PR preview handling
🔍 Provides Rich Feedback - Posts deployment details, app URLs, and metadata directly to your PRs
🏢 Meets Enterprise Standards - Built for Equinor's Azure infrastructure with full security compliance
Think of it as your "deploy button" for Fusion apps - one action that handles everything from authentication to deployment feedback.
- 🔐 Flexible Authentication: Use either pre-acquired Fusion tokens or Azure Service Principal credentials
- 🏗️ Artifact Publishing: Support for zip archive files (.zip) or source-based publishing from the working directory
- ⚡ Efficient Processing: Direct zip file reading without temporary file extraction
- ✅ Comprehensive Validation: Validated inputs, file formats, and authentication methods
- 🌍 Multi-Environment: Support for ci, tr, fprd, fqa, and next environments
- 🔄 PR Deployments: Automatic preview deployments for pull requests
- 🧪 Fully Tested: 100% test coverage with comprehensive unit tests
- 🔍 Detailed Logging: Clear output and error messages for debugging
- 📝 Rich Metadata: Extracts app information from metadata.json (name -> appKey) and posts deployment details to PRs
👉 For comprehensive examples and deployment patterns, see our Complete Use Cases Guide
This guide covers 9+ detailed scenarios including:
- 🚀 Basic to Enterprise deployment pipelines
- 🔐 Azure Service Principal with GitHub Environments
- 🔄 Pull Request previews and multi-environment workflows
- 🏢 Monorepo deployments and custom configurations
- 🐛 Debugging and troubleshooting workflows
Whether you're getting started or implementing enterprise-grade deployments, the complete guide has copy-paste ready examples for your use case.
name: Deploy to Fusion
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Publish to Fusion
uses: equinor/fusion-action-app-publish@v1
with:
fusion-token: ${{ secrets.FUSION_TOKEN }}
env: 'fprd'
artifact: './app-bundle.zip'
tag: 'v1.0.0'name: Deploy to Fusion
on:
push:
branches: [main]
# Required for Azure OIDC authentication
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Publish to Fusion
uses: equinor/fusion-action-app-publish@v1
with:
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
env: 'fprd'
artifact: './app-bundle.zip'name: PR Preview
on:
pull_request:
branches: [main]
permissions:
id-token: write
contents: read
pull-requests: write # For posting deployment comments
jobs:
deploy-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Deploy PR Preview
id: deploy
uses: equinor/fusion-action-app-publish@v1
with:
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
env: 'ci' # Will create pr-{number} deployment
prNR: ${{ github.event.number }}
artifact: './app-bundle.zip'When artifact is omitted, the action publishes directly from the working directory using ffc app publish without a prebuilt bundle. This simplifies PR workflows by letting the CLI handle the build.
name: PR Preview (Source)
on:
pull_request:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install dependencies
run: npm ci
- name: Deploy PR Preview from source
uses: equinor/fusion-action-app-publish@v1
with:
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
prNR: ${{ github.event.number }}| Input | Description | Required | Default |
|---|---|---|---|
fusion-token |
Pre-acquired Fusion bearer token | No | - |
azure-client-id |
Azure Service Principal Client ID | No | - |
azure-tenant-id |
Azure Tenant ID | No | - |
azure-resource-id |
Fusion audience/resource ID for token acquisition (optional - auto-detected from environment) | No | - |
env |
Target environment (ci/tr/fprd/fqa/next) | No | ci |
prNR |
Pull Request number (used with env=ci) | No | - |
artifact |
Path to built artifact file (.zip). If omitted, publishes from working directory. | No | - |
config |
Path to fusion app config file (optional) | No | - |
tag |
Tag to apply to the deployment | No | latest |
working-directory |
Working directory for commands | No | . |
snapshot |
Enable snapshot versioning. Use true for auto-generated ID or provide custom identifier (e.g., pr-123) |
No | - |
| Output | Description |
|---|---|
app-url |
Direct URL to the published application |
portal-url |
Fusion portal URL for managing the application |
target-env |
Resolved target environment |
app-name |
Application name from metadata |
app-version |
Application version from metadata |
publish-info |
Formatted publish information for PR comments |
auth-type |
Authentication type used (token or service-principal) |
is-token |
Whether fusion-token authentication was used (boolean) |
is-service-principal |
Whether Azure Service Principal authentication was used (boolean) |
The action provides two distinct functions for authentication validation:
Validates the format and structure of Fusion bearer tokens:
- Ensures token is a non-empty string
- Validates BEARER prefix format
- Supports alphanumeric characters, dots, dashes, and underscores
Detects authentication type and validates Service Principal credentials:
- Returns authentication type (
tokenorservice-principal) - Validates Azure Service Principal credentials (requires azure-client-id and azure-tenant-id)
- Handles credential precedence when both types are provided
Use this method if you already have a Fusion bearer token:
- uses: equinor/fusion-action-app-publish@v1
with:
fusion-token: ${{ secrets.FUSION_TOKEN }}
env: 'fprd'
artifact: './app-bundle.zip'Use this method to let the action acquire a token using Azure Service Principal:
# Requires OIDC permissions
permissions:
id-token: write
contents: read
# In job steps:
- uses: equinor/fusion-action-app-publish@v1
with:
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
env: 'fprd'
artifact: './app-bundle.zip'Authentication Priority: When both authentication methods are provided, the action prioritizes Azure Service Principal authentication over tokens. This allows for future extensibility and consistent behavior.
The action now automatically detects the appropriate Azure Resource ID based on the target environment when not explicitly provided:
- Non-production environments (
ci,fqa,tr,next): Usesapi://fusion.equinor.com/nonprod - Production environment (
fprd): Usesapi://fusion.equinor.com/prod - Unknown environments: Defaults to non-production resource ID with a warning
You can still explicitly specify the Azure Resource ID if needed:
- uses: equinor/fusion-action-app-publish@v1
with:
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-resource-id: "custom-resource-id" # Override auto-detection
env: 'fprd'Note: The auto-detection feature provides new scope patterns that are not yet implemented in the app-service backend. This functionality is prepared for future service updates.
For Fusion Token method:
FUSION_TOKEN: Your pre-acquired Fusion bearer token
For Service Principal method:
AZURE_CLIENT_ID: Azure Application (client) IDAZURE_TENANT_ID: Azure Directory (tenant) IDFUSION_RESOURCE_ID: Fusion API resource/audience ID
- Create an Azure App Registration
- Create a client secret
- Assign appropriate permissions to access Fusion APIs
- Note down the Client ID, Tenant ID, and Resource ID
The action validates against these environments:
ci- Continuous Integration / Pull Request previewstr- Test/Trial environmentfprd- Full Productionfqa- Full Quality Assurancenext- Next/Beta environment
When using env: 'ci' with a prNR, the action automatically creates preview deployments tagged as pr-{number}.
The artifact input is optional. When omitted, the action publishes directly from the working directory using ffc app publish (source-based publish). This is ideal for PR preview workflows where you want the CLI to handle the build.
When providing an artifact, the action supports:
.zipfiles - Standard ZIP archives (only format supported currently)
app-bundle/
├── index.html
├── bundle.js
├── styles.css
└── metadata.json # Required for metadata extraction
The action will automatically extract metadata from metadata.json when present. The extraction process uses unzip -p to read the metadata directly from the zip archive without creating temporary files, making it more efficient and faster.
{
"name": "fusion-framework-cookbook-app-react",
"version": "4.1.8"
}The name field will be used as the app key for deployment.
"Artifact not found"
- Ensure the build step runs before publish
- Check that
artifactpath is correct - Verify
working-directoryis set properly - Use absolute paths or verify relative paths from working directory
"Invalid environment"
- Use one of: ci, tr, fprd, fqa, next
- Check spelling and case sensitivity
- Environment names are case-sensitive
"Missing authentication credentials"
- Provide either
fusion-tokenOR all SP credentials - Don't provide both authentication methods
- Ensure all required Azure credentials are set (client-id, tenant-id, resource-id)
"Token seems unusually short"
- Verify your Fusion token is complete and valid
- Check token hasn't expired
- Ensure token includes "BEARER_" prefix
"Manifest file not found"
- Ensure
app-manifest.jsonexists in your bundle - Check bundle structure matches requirements
- Verify file names are correct (case-sensitive)
"Metadata file not found"
- Ensure
metadata.jsonexists in your bundle - Check JSON syntax is valid
- Verify required fields (name, version) are present
"Config file validation failed"
- Ensure config file exists at specified path
- Verify config file contains valid JSON
- Check file permissions
"Bundle extraction failed"
- Verify zip file is not corrupted
- Check zip file contains required structure
- Ensure bundle was created properly by your build process
Add debug output to your workflow:
- name: Debug Bundle Info
run: |
echo "Environment: ${{ inputs.env }}"
echo "Artifact path: ${{ inputs.artifact }}"
echo "Working directory: $(pwd)"
ls -la ${{ inputs.artifact }}
# Check bundle contents
if [[ "${{ inputs.artifact }}" == *.zip ]]; then
echo "Bundle contents:"
unzip -l ${{ inputs.artifact }}
# Check for required files
echo "Checking for required files:"
unzip -l ${{ inputs.artifact }} | grep -E "(metadata\.json|app-manifest\.json)" || echo "⚠️ Required files missing"
fi
- name: Validate Bundle Structure
run: |
# Extract and validate metadata.json
unzip -p ${{ inputs.artifact }} metadata.json > /tmp/metadata.json 2>/dev/null || echo "❌ metadata.json missing"
if [[ -f /tmp/metadata.json ]]; then
echo "✅ metadata.json found:"
cat /tmp/metadata.json | jq .
fi
# Extract and validate app-manifest.json
unzip -p ${{ inputs.artifact }} app-manifest.json > /tmp/manifest.json 2>/dev/null || echo "❌ app-manifest.json missing"
if [[ -f /tmp/manifest.json ]]; then
echo "✅ app-manifest.json found:"
cat /tmp/manifest.json | jq .
fi| Error | Meaning | Solution |
|---|---|---|
ENOENT |
File or directory not found | Check paths and ensure files exist |
EACCES |
Permission denied | Check file permissions |
Invalid JSON |
JSON parsing failed | Validate JSON syntax in metadata/config files |
Missing appKey |
app-manifest.json missing required field | Add appKey to manifest |
Missing name/version |
metadata.json missing required fields | Add name and version to metadata |
Auth validation failed |
Authentication credentials invalid | Check token format or SP credentials |
Unsupported environment |
Environment not in allowed list | Use: ci, tr, fprd, fqa, or next |
Run the test suite to validate changes:
# Run all tests
pnpm test
# Run tests with coverage
pnpm run test:coverage
# Test individual validation scripts
node scripts/validate-artifact.js
node scripts/validate-env.js
node scripts/validate-is-token-or-azure.js- Fork the repository
- Create a feature branch
- Make your changes
- Run the test suite:
pnpm test - Ensure 100% test coverage:
pnpm run test:coverage - Update documentation if needed
- Submit a pull request
See CONTRIBUTING.md for detailed development guide.
MIT - see LICENSE file for details.
For issues related to:
- GitHub Action: Open an issue in this repository
- Fusion Framework CLI: Check @equinor/fusion-framework-cli
- Fusion Platform: Contact the Fusion Core team Github Action for publishing Fusion applications