Configure Promotion Workflows
Create, run, and manage Promotion Workflows
Workflows are automated processes designed to orchestrate tasks, checks, and actions in a defined sequence to achieve a specific outcome. In the context of GitOps promotions, Promotion Workflows automate tests and tasks before and after changes are promoted in environments.
Promotion Workflows and Argo Workflows
Promotion Workflows are Argo Workflows that include a specific annotation identifying them for promotion use. You can harness the full capabilities of Argo Workflows and integrate them seamlessly into the GitOps promotion process.
If you are not familiar with Argo Workflows, refer to their official documentation.
We also have several articles at our learning center on all aspects of Argo Workflows.
See also Annotation attribute for Promotion Workflows.
Pre-Action and Post-Action Workflows
Promotion Workflows though optional in the promotion process, play a critical role in ensuring that the promoted changes to target environments meet the necessary standards for quality and performance.
Our GitOps promotion process allows you to run Promotion Workflows at different stages of the process:
- Before the changes are applied through Pre-Action Workflows Pre-Action Workflows validate the readiness of the environment for the changes. These workflows can include tasks such as smoke tests, security scans, or dependency checks.
- After the changes are applied through Post-Action Workflows Post-Action Workflows validate the success of the promotion after the changes are committed. Such workflows can run performance testing, data integrity checks, or notifying stakeholders about the update status.
See Promotion Workflow examples.
Using Promotion Workflows in the promotion process
After creating Promotion Workflows, there are two ways to use them in the promotion process depending on the level of control and scalability you need:
-
Manual selection
When triggering a promotion manually, you can select specific Pre- and Post-Action Workflows to run for the target environment. This approach is ideal for single-environment promotions or when you need granular control over the workflows for a specific change.
Example:
During a drag-and-drop promotion, you might choose a Pre-Action Workflow to run integration tests and a Post-Action Workflow to send Slack notifications for the target environment. -
Controlled automation with policies
For scalable, automated usage, you can associate Promotion Workflows with Promotion Policies. Promotion Policies govern promotion behavior according to predefined criteria to create reusable promotion patterns for environments. With this approach, you can match workflows to environments or products, ensuring consistent behavior in multi-environment promotion flows. You can also combine workflows with specific promotion actions, such as committing changes in pre-production and creating pull requests in production.
Example:
Assign a validation workflow for all staging environments and a performance testing workflow for production environments.
Arguments in Pre-Action and Post-Action Workflows
Codefresh passes a set of arguments it retrieves during the promotion process to both Pre- and Post-Action Workflows. You can use these as dynamic data throughout the promotion lifecycle.
See Arguments in Pre-Action and Post-Action Workflows.
Manage workflows and workflow instances
After creating Promotion Workflows, you can manage workflows and workflow instances.
Promotion Workflow examples
Below are examples of different types of workflows designed to address specific requirements at various stages of the GitOps promotion process.
- Testing workflows: Running unit and smoke tests for example to validate and verify that the promoted change is functional in the target environment.
- Notification workflows: Send updates or alerts to stakeholders via tools like Slack or email.
- Performance testing workflows: For running benchmarks or load tests to validate performance post-promotion.
- Validation workflows: Ensure compliance with security, quality, or policy standards before deployment.
- Rollback workflows: Automatically revert changes if a promotion fails validation or post-action checks.
Workflow settings in Shared Repo
Once configured and committed, Workflow settings are saved as a CRD (Custom Resource Definition) within the Shared Configuration Repository in the GitOps Runtime selected as the Configuration Runtime.
The path in the Shared Configuration Repo is <gitops-runtime>/<shared-configuration-repo>/resources/control-planes/promotion-workflows/
.
See Shared Configuration Repository and Designating Configuration Runtimes.
YAML examples
Here are some examples of Promotion Workflows with different objectives and run at different stages of the promotion process.
- Example 1: Pre-Action Workflow with application sync check
- Example 2: Pre-action Workflow combining smoke test and Slack notification
- Example 3: Post-Action Workflow to close Jira ticket
Example 1: Pre-Action application sync check test
This Pre-action Workflow performs a preliminary validation by echoing a sync message for the application being promoted.
The workflow confirms that the argument APP_NAME
is correctly passed to it and right application is being promoted.
# DO NOT REMOVE the following attributes:
# annotations.codefresh.io/workflow-origin (identifies type of Workflow Template as Promotion Workflow)
# annotations.version (identifies version of Promotion Workflow used)
# annotations.description (identifies intended use of the Promotion Workflow)
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: pre-action
annotations:
codefresh.io/workflow-origin: promotion
version: 0.0.1
description: 'promotion workflow template'
spec:
serviceAccountName: promotion-template
arguments:
parameters:
- name: APP_NAME
description: The name of the application being promoted.
entrypoint: echo-pre-action
templates:
- name: echo-pre-action
script:
image: alpine
command:
- sh
source: |
echo "syncing "
Example 2: Pre-Action smoke test with Slack notification
A more complex Pre-Action Workflow, the workflow in this example executes a smoke test and sends a Slack alert if the smoke test fails. The workflow identifies failures before changes are committed and promoted, and alerts stakeholders of the failures.
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: smoke-test-pre-action
annotations:
codefresh.io/workflow-origin: promotion
version: 0.0.1
description: 'Pre-action smoke test with Slack notification'
spec:
serviceAccountName: promotion-template
arguments:
parameters:
- name: APP_NAME
description: The name of the application being promoted.
entrypoint: smoke
onExit: slack-alert
templates:
- name: smoke
inputs:
parameters:
- name: NB_TESTS
value: 100
- name: THRESHOLD
value: 30
- name: TEST_RATE
value: 50
script:
image: bash:5.2.26
command: ["/usr/local/bin/bash"]
source: |
num_tests=
error=0
success=0
test_rate=
suite_threshold=
# Generate random test results
for ((i=1; i<=$num_tests; i++)); do
rand_num=$((RANDOM % 100 + 1))
if ((rand_num < test_rate ))
then
echo "Test $i: FAILED ($rand_num)"
((error++))
else
echo "Test $i: PASSED ($rand_num)"
((success++))
fi
done
success_rate=$((success * 100 / num_tests))
echo "Success Rate: $success_rate%"
if ((success_rate < suite_threshold))
then
echo "Test Suite: FAILED"
exit 1
else
echo "Test Suite: PASSED"
exit 0
fi
- name: slack-alert
dag:
tasks:
- name: send-message
templateRef:
name: argo-hub.slack.0.0.2
template: post-to-channel
when: " != Succeeded"
arguments:
parameters:
- name: SLACK_CHANNEL
value: 'topic-codefresh-demo'
- name: SLACK_MESSAGE
value: 'Smoke test failed for . Check logs at https://g.codefresh.io/2.0/workflows/'
- name: SLACK_TOKEN
value: slack-token
- name: LOG_LEVEL
value: "info"
Example 3: Post-Action soak test
This example is of a Post-Action Promotion Workflow that uses a script template to display application details, commit information, and the Argo CD host, taking these parameters from the promotion flow process.
# DO NOT REMOVE the following attributes:
# annotations.codefresh.io/workflow-origin (identifies type of Workflow Template as Promotion Workflow)
# annotations.version (identifies version of Promotion Workflow used)
# annotations.description (identifies intended use of the Promotion Workflow)
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: soak-test
annotations:
codefresh.io/workflow-origin: promotion
version: 0.0.1
argo-hub/version: 0.0.2
argo-hub/description: >-
This Workflow Template is an example of a post-promotion workflow that
uses a script template to display application details, commit information,
and the Argo CD host, taking these parameters from the promotion flow
process.
argo-hub/categories: promotion example workflow
argo-hub/license: MIT
argo-hub/owner_name: Eti Zaguri
argo-hub/owner_email: eti.zaguri@codefresh.io
argo-hub/owner_avatar: https://avatars.githubusercontent.com/u/85868206
argo-hub/owner_url: https://github.com/eti-codefresh
argo-hub/icon_url: >-
https://cdn.jsdelivr.net/gh/codefresh-io/argo-hub@main/examples/post-promotion-starter/assets/icon.svg
argo-hub/icon_background: '#f4f4f4'
spec:
arguments:
parameters:
- name: APP_NAMESPACE
- name: APP_NAME
- name: REPO_URL
- name: BRANCH
- name: PATH
- name: COMMIT_SHA
value: ''
- name: COMMIT_MESSAGE
value: ''
- name: COMMIT_AUTHOR
value: ''
- name: COMMIT_DATE
value: ''
serviceAccountName: argo-hub.post-promotion-starter.0.0.2
entrypoint: echo
templates:
- name: echo
metadata:
annotations:
argo-hub-template/description: >-
Echo the commit parameters and argo cd host from the promotion flow
process
argo-hub-template/icon_url: >-
https://cdn.jsdelivr.net/gh/codefresh-io/argo-hub@main/examples/post-promotion-starter/assets/icon.svg
argo-hub-template/icon_background: '#f4f4f4'
script:
image: alpine
command:
- sh
source: >
echo "syncing
/
from branch
path "
if [[ -n "" ]]; then
echo "commit SHA: "
fi
if [[ -n "" ]]; then
echo "commit author: "
fi
if [[ -n "" ]]; then
echo "commit message: "
fi
if [[ -n "" ]]; then
echo "commit date: "
fi
Parameters in Pre-Action and Post-Action Workflows
Pre-Action and Post-Action Workflows can use default parameters retrieved from application manifest data, and user-defined custom parameters to adapt dynamically to specific environments and processes.
Default parameters
The table describes the default parameters and values passed to Pre- and Post-Action Workflows.
The same set of parameters are passed also for pull requests (GitHub only), after the pull request is merged.
At the simplest levels, you can display the details from the parameters in notifications. In more advanced scenarios, you can customize the workflow execution based on specific parameters.
Parameters | Description | Pre-Action Workflow | Post-Action Workflow |
---|---|---|---|
APP_NAMESPACE |
The namespace where the application is deployed to. For example, gitops . |
✅ | ✅ |
APP_NAME |
The name of the specific application the Promotion Workflows and the Promotion Action pertain to. For example, trioapp-staging . |
✅ | ✅ |
REPO_URL |
The Git repository with the application settings, as defined in the application’s configuration. See Source settings for applications. | ✅ | ✅ |
BRANCH |
The specific Git branch to which to promote changes. For example, main . |
✅ | ✅ |
PATH |
The relative path within the repository defined by REPO_URL to the directory or file containing the application’s configuration. See Source settings for applications. |
✅ | ✅ |
RUNTIME |
The name of the GitOps Runtime the application being promoted is associated with. | ✅ | ✅ |
COMMIT_SHA |
The unique identifier (SHA) of the commit, generated by Git, including the precise set of changes addressed by the commit. Can be used as a trigger condition in Promotion Flows configured for a product. | ✅ | |
COMMIT_AUTHOR |
The name of the user who made the commit. Useful for tracking changes and for notifications. | ✅ | |
COMMIT-MESSAGE |
The text in the commit message associated with the code change that triggered the promotion, providing context for the changes introduced by the commit. | ✅ | |
COMMIT-DATE |
The date and time when the commit was made. Useful to correlate the commit with other events and understand the timeline of changes. | ✅ |
Custom global parameters
In Pre-Action Workflows, you can define custom parameters as global outputs, making them available as input parameters in subsequent Post-Action Workflows. This feature provides a seamless way to pass data across workflows and create complex automation scenarios.
In the Pre-Action Workflow, any parameter marked with a globalName
in its outputs
definition becomes a global parameter.
These parameters are then available for the Post-Action Workflow.
outputs:
parameters:
- name: JIRA_ID
globalName: JIRA_ID
valueFrom:
path: /tmp/JIRA_ID
Custom globalName
argument usage example
This is an example of a Pre-Action Workflow that simulates creating a Jira ticket with the data retreived from the application manifest and outputs the ticket ID as a global parameter. The Post-Action Workflow simulates using the ID as an input parameter to close the ticket.
Pre-Action Workflow example with Jira ID as global parameter
Main features:
- Workflow parameters
The following parameters are passed to the Pre-Action Workflow:
- Application details:
APP_NAMESPACE
,APP_NAME
- Source repository details:
REPO_URL
,BRANCH, PATH
- Application details:
-
Argo CD application fetch task
Theargocd-get
task fetches application details using Argo CD’s CLI, storing the application manifest for downstream tasks. - Jira ticket creation task
Thejira-create-ticket
task generates a simulated Jira ticket ID based on the application manifest.
TheJIRA_ID
parameter is marked with aglobalName
to allow it to be passed to post-action workflows seamlessly.
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: pre-action-argo-cd-jira-example
annotations:
codefresh.io/workflow-origin: promotion
codefresh.io/promotion-stage: pre-action
version: 0.0.1
description: 'a demo jira-open-ticket wf. reads argo-cd app information, outputs (dummy) JIRA_ID value'
spec:
serviceAccountName: pre-action-sa
entrypoint: dag
arguments:
parameters:
- name: APP_NAMESPACE
- name: APP_NAME
- name: REPO_URL
- name: BRANCH
- name: PATH
templates:
- name: dag
inputs:
parameters:
- name: APP_NAMESPACE
- name: APP_NAME
- name: REPO_URL
- name: BRANCH
- name: PATH
dag:
tasks:
- name: argocd-get
template: argocd-get-tmpl
arguments:
parameters:
- name: ARGOCD_SERVER
value: argo-cd-server:80 # or whatever service name you end up using
- name: APP_NAME
value: ""
- name: TOKEN_SECRET
value: argocd-token
- name: TOKEN_SECRET_KEY
value: token
- name: jira-create-ticket
depends: "argocd-get"
template: jira-create-ticket-tmpl
arguments:
parameters:
- name: APP_MANIFEST
value: ""
- name: argocd-get-tmpl
inputs:
parameters:
- name: ARGOCD_SERVER
- name: APP_NAME
- name: TOKEN_SECRET
default: argocd-token
- name: TOKEN_SECRET_KEY
default: token
outputs:
parameters:
- name: APP_MANIFEST
# globalName: APP_MANIFEST # optional - any global output will reach the post-action as well
valueFrom:
path: /tmp/result.json
script:
name: app-get
image: quay.io/codefreshplugins/argo-hub-workflows-argocd-versions-0.0.1-images-argocd-cli:main
env:
- name: APP_NAME
value: ""
- name: ARGOCD_SERVER
value: ""
- name: ARGOCD_AUTH_TOKEN
valueFrom:
secretKeyRef:
name: ""
key: ""
- name: ARGOCD_OPTS
value: --grpc-web --plaintext
command:
- sh
source: |
argocd app get ${APP_NAME} --output json > /tmp/result.json
- name: jira-create-ticket-tmpl
inputs:
parameters:
- name: APP_MANIFEST
outputs:
parameters:
- name: JIRA_ID
globalName: JIRA_ID
valueFrom:
path: /tmp/JIRA_ID
script:
image: alpine:3.20
command:
- sh
source: |
echo "create jira ticket with data from the inputs.prameters.APP_MANIFEST"
sleep 5
RANDOM_HASH=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13)
echo "JIRA-ticket-id-${RANDOM_HASH}" > /tmp/JIRA_ID
Post-Action Workflow with Jira ID
Main features:
- Workflow parameters
The following parameters are passed to the Post-Action Workflow:- Application details:
APP_NAMESPACE
,APP_NAME
- Source repository details:
REPO_URL
,BRANCH, PATH
- Promotion metadata:
COMMIT_SHA
,COMMIT_MESSAGE
,COMMIT_AUTHOR
,COMMIT_DATE
- Jira ticket ID:
JIRA_ID
- Application details:
- Close Jira ticket task
Uses theclose-jira task
to call a script that simulates closing the JIRA ticket by using the providedJIRA_ID
.
The task output will show:Closing JIRA ticket: <JIRA_ID> followed by JIRA ticket <JIRA_ID> closed
. - Log summary task
After closing the Jira ticket, theecho
task logs and outputs all provided contextual information, including the promotion details from the arguments passed to the workflow.
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: post-action-jira-example
annotations:
codefresh.io/workflow-origin: promotion
codefresh.io/promotion-stage: post-action
version: 0.0.1
description: 'a demo jira-close-ticket wf. expects (dummy) JIRA_ID argument'
spec:
serviceAccountName: post-action-sa
entrypoint: dag
arguments:
parameters:
- name: APP_NAMESPACE
- name: APP_NAME
- name: REPO_URL
- name: BRANCH
- name: PATH
- name: COMMIT_SHA
value: ""
- name: COMMIT_MESSAGE
value: ""
- name: COMMIT_AUTHOR
value: ""
- name: COMMIT_DATE
value: ""
- name: JIRA_ID
templates:
- name: dag
inputs:
parameters:
- name: APP_NAMESPACE
- name: APP_NAME
- name: REPO_URL
- name: BRANCH
- name: PATH
- name: COMMIT_SHA
- name: COMMIT_MESSAGE
- name: COMMIT_AUTHOR
- name: COMMIT_DATE
- name: JIRA_ID
dag:
tasks:
- name: jira-close
template: jira-close-tmpl
arguments:
parameters:
- name: JIRA_ID
value: ""
- name: echo
depends: "jira-close"
template: echo-tmpl
arguments:
parameters:
- name: APP_NAMESPACE
value: ""
- name: APP_NAME
value: ""
- name: REPO_URL
value: ""
- name: BRANCH
value: ""
- name: PATH
value: ""
- name: COMMIT_SHA
value: ""
- name: COMMIT_MESSAGE
value: ""
- name: COMMIT_AUTHOR
value: ""
- name: COMMIT_DATE
value: ""
- name: jira-close-tmpl
inputs:
parameters:
- name: JIRA_ID
script:
image: alpine:3.20
env:
- name: JIRA_ID
value: ""
command:
- sh
source: |
echo "got JIRA_ID \"${JIRA_ID}\""
sleep 5
echo "after handling jira in post action"
- name: echo-tmpl
inputs:
parameters:
- name: APP_NAMESPACE
- name: APP_NAME
- name: REPO_URL
- name: BRANCH
- name: PATH
- name: COMMIT_SHA
- name: COMMIT_MESSAGE
- name: COMMIT_AUTHOR
- name: COMMIT_DATE
outputs:
parameters:
- name: RESULT
valueFrom:
path: /tmp/result
globalName: RESULT
script:
image: alpine:3.20
command:
- sh
source: |
converted_date=$(date -d "" +"%a %b %d %H:%M:%S %Y %z")
echo "post action for \"/\""
echo "repoUrl: , branch: , path: "
echo ""
echo "commit "
echo "Author: "
echo "Date: ${converted_date}"
echo ""
echo " "
echo ""
echo "{\"POST_ACTION_RESULT\": "\Success\""}" > /tmp/result
Annotation attribute for Promotion Workflows
An Argo Workflow or a Workflow Template is classified as a Promotion Workflow only when the following annotation is present in the workflow manifest:
metadata.annotations: codefresh.io/workflow-origin: promotion
This annotation in the Promotion Workflow’s manifest ensures that:
- The Promotion Workflow is displayed in the Promotion Workflows list and can be managed there
- You can assign the Promotion Workflows in Promotion Policies
- Select Promotion Workflows within Promotion Flows
Create Promotion Workflows
Create a Promotion Workflow from scratch, use the base Promotion Workflow Template, or use one of the predefined Promotion Workflows in Codefresh.
Whichever method you use to create your Promotion Workflow, make sure you include the annotation in the manifest to classify and use it as a Promotion Workflow.
- In the Codefresh UI, from Promotions in the sidebar, select Promotion Workflows.
- Click Add Promotion Workflow.
- Define the following:
- Name: The name of the Promotion Workflow.
The name must be unique in the cluster, and must match Kubernetes naming conventions. - Description : The intended use of the Promotion Workflow.
The description is added as an annotation to the YAML file. It is also displayed in the Promotion Workflows list in the UI. - Resource Filename: The name of the YAML resource file with the configuration settings for the Promotion Workflow, by default, identical to the Name of the Promotion Workflow. You can change as needed.
- Name: The name of the Promotion Workflow.
- Click Add.
- Select Blank Skeleton File and click Next. The YAML is displayed on the right populated with the settings you defined.
- Note the instructions at the top of the YAML file.
- If needed, change
metadata.annotations.version
. The version is displayed in the Promotion Workflows list in the UI. You should update it manually when there are changes. - To test the Promotion Workflow with the current settings before committing the changes, click Run.
- Make any updates needed.
- Commit the changes.
When the YAML file is synced to the cluster, it is displayed in the Promotion Workflows list.
Promotion Workflow list
All Workflows which include metadata.annotations: codefresh.io/workflow-origin: promotion
are displayed in the Promotion Workflows list.
The Description and Version information are retrieved from the manifest if these are specified there.
The Promotion Workflows list is also the centralized location from which you can manage both Workflows and Workflow instances. See Managing Promotion Workflows and Managing Workflow instances.
Managing Promotion Workflows
After you create a Promotion Workflow, you can:
- Optimize the manifest by updating steps or refining the logic to better suit evolving requirements
- Locally validate the current version of the manifest with different values for parameters
- Copy and delete Promotion Workflows
Update Promotion Workflow manifests
Update and optimize the Promotion Workflow manifest including steps, actions, and parameters, to adapt to changing requirements.
When triggered, the Promotion Workflow uses the current version of the manifest, ensuring that the Workflow execution instance always uses the latest configurations and optimizations.
You can:
- Toggle between the Git State, Desired State, and Live State
- Render Diff views of all three states
- Update manifest
Changes to the manifest do not affect past execution instances as the manifest is updated independently of individual workflow executions.
Validate Promotion Workflow parameters
When you create a Promotion Workflow or modify the manifest of an existing workflow, you can validate the new workflow or the changes made before committing them to Git.
The Run option supplements the automatic inline validations, allowing you to verify parameter and confirm that the workflow behaves as expected, or change parameter values to test behavior.
The option runs the specific Promotion Workflow in the cluster, verifying all actions and steps in the workflow, such as sending notifications, running pre-action validations or post-action test.
- In the Codefresh UI, from Promotions in the sidebar, select Promotion Workflows.
- Click the name of the Promotion Workflow to validate.
- Click Run at the top-right. Codefresh displays the parameters passed in the Promotion Workflow.
- Modify as needed.
- Click Run at the bottom of the form.
Copy/delete Promotion Workflows
Copy an existing Promotion Workflow to create a new Promotion Workflow with the same manifest configuration.
Delete unused legacy Promotion Workflows. Deleting a Promotion Workflow removes it from the Promotion Workflow list, from the Promotion Policies it is configured in, and from the Promotion Flows.
Both options are available in the context menu of the selected Promotion Workflow.
Managing Workflow instances
Workflow instances are the specific execution instances of the Promotion Workflow.
You can:
- View instances of a Promotion Workflow In addition to the status which is prominently displayed on the right for each execution instance, you can filter by products, environments and applications to get to the instances of interest to you.
-
Analyze the version of the manifest used for the instance with the configuration, parameters, artifacts (Workflow summary)
- Take action on a completed or failed workflow (Workflow actions)
- Resubmit: Rerun or re-execute the Workflow. Resubmitting a Workflow, creates a new instance of the Workflow. You can resubmit both successful and failed workflows.
- Retry: Rerun the workflow instance from the point of error. Unlike Resubmit, Retry does not create a new workflow instance.
- Delete an instance (Workflow actions)
- Analyze individual steps of the workflow (Workflow steps)
- The header displays the name of the step, its status, the step-type, the date of the most recent update, and duration.
- The tabs displayed differ according to the step type:
- The Summary, Manifest, Containers, Inputs, Outputs tabs are displayed for all almost all step types.
- The Logs tab is displayed for Pod step types.
- Event-step types display Manifest, Summary, and Payload. For Cron and Unknown event types, only the Event Sources are shown.
- View detailed logs to troubleshoot execution (Workflow logs) View online logs for ongoing or completed Workflows. As with logs in any standard terminal, you can copy/cut/paste log info. The commands differ based on the OS.
Promotion Workflows in product release views
When a promotion is triggered automatically or manually, a release is created for the product and displayed in the Releases tab.
Clicking the Release ID displays the ongoing or completed view of the promotion orchestration across the environment.
Each environment displays the Pre-Action or Post-Action workflows assigned to it, including its steps for on-going releases. The collective status of the workflows determines the promotion status of an environment.
See Promotion Workflows in product releases.
Related articles
Configure Promotion Flows
Configure Promotion Policies
Trigger promotions
Tracking product releases
Promotions: End-to-end guide
About promotions