How to share data between jobs
To pass data, such as your BUILD_STAGE value, from one job to a subsequent job,
you have two primary methods in Gitea/GitHub Actions:
1. Use Job Outputs (Recommended for small string values)
You can define the variable as an “output” of the first job and then reference that output in a dependent job using the needs context.
Job 1 (build) – Sets the output:
jobs:
build:
runs-on: ubuntu-latest
outputs:
build_stage_output: ${{ steps.set_stage.outputs.BUILD_STAGE }} <em># Map step output to job output</em>
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set BUILD_STAGE environment variable and output
id: set_stage <em># Give this step an ID</em>
run: |
COMMIT_MSG="${{ github.event.head_commit.message }}"
BUILD_STAGE="DEV"
if [[ "$COMMIT_MSG" == *"#ready-for-qa"* ]]; then
BUILD_STAGE="QA"
elif [[ "$COMMIT_MSG" == *"#ready-for-prod"* ]]; then
BUILD_STAGE="PROD"
fi
# Write to GITHUB_OUTPUT to make it a step output
echo "BUILD_STAGE=$BUILD_STAGE" >> $GITHUB_OUTPUT
shell: bash
Job 2 (deploy) – Reads the output:
deploy:
runs-on: ubuntu-latest
needs: [build] <em># Declare dependency on the build job</em>
steps:
- name: Use BUILD_STAGE from previous job
run: |
# Access the variable using the needs context
STAGE_VAR="${{ needs.build.outputs.build_stage_output }}"
echo "The build stage from the previous job is: $STAGE_VAR"
2. Use Artifacts (Recommended for files or large data)
If the data is large or a file (e.g., a build artifact or a configuration file), you can upload it in the first job and download it in the second job using the actions/upload-artifact and actions/download-artifact actions.
Yes, you can use artifacts to pass data (in the form of files) between different jobs. This is the standard and correct method for cross-job data sharing in Gitea Actions.
Here is an example demonstrating how to create a file containing the BUILD_STAGE in the first job, upload it as an artifact, and then download and read it in the second job.
Workflow Example using Artifacts
name: Conditional Build Stage with Artifacts
on: [push]
jobs:
<em># --- Job 1: Build & Upload Artifact ---</em>
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Determine and save BUILD_STAGE to a file
id: set_stage_file
run: |
COMMIT_MSG="${{ github.event.head_commit.message }}"
BUILD_STAGE="DEV" # Default value
if [[ "$COMMIT_MSG" == *"#ready-for-qa"* ]]; then
BUILD_STAGE="QA"
elif [[ "$COMMIT_MSG" == *"#ready-for-prod"* ]]; then
BUILD_STAGE="PROD"
fi
# Create a directory and save the variable to a file
mkdir -p ./artifact_output
echo "$BUILD_STAGE" > ./artifact_output/build_stage.txt
echo "Determined stage: $BUILD_STAGE"
shell: bash
- name: Upload BUILD_STAGE artifact
uses: actions/upload-artifact@v4 <em># Use the upload-artifact action</em>
with:
name: build-stage-artifact <em># Name for the artifact</em>
path: ./artifact_output/build_stage.txt <em># The file path to upload</em>
<em># --- Job 2: Download & Use Artifact ---</em>
deploy:
runs-on: ubuntu-latest
needs: [build] <em># This job MUST wait for the 'build' job to complete</em>
steps:
- name: Download BUILD_STAGE artifact
uses: actions/download-artifact@v4 <em># Use the download-artifact action</em>
with:
name: build-stage-artifact <em># Must match the name used in the upload job</em>
path: ./downloaded_artifact <em># Directory where the file will be downloaded</em>
- name: Read the BUILD_STAGE from the file
run: |
# The file will be in the specified path from the download step
STAGE_VALUE=$(cat ./downloaded_artifact/build_stage.txt)
echo "The build stage passed from the previous job is: $STAGE_VALUE"
# You can now use $STAGE_VALUE in subsequent commands within this step/job
if [ "$STAGE_VALUE" == "PROD" ]; then
echo "Deploying to Production environment..."
# Add your production deployment logic here
fi
shell: bash
In a Gitea Actions workflow file (which is the Gitea equivalent of a deploy.yaml for actions), the env keyword can be placed at three different levels to define environment variables:
- Workflow level: Defined at the top level of the YAML file, the environment variables are available to all jobs and steps within the workflow.
- Job level: Defined within a specific
job, the variables are available to all steps within that job. - Step level: Defined within a specific
step, the variables are only available to that particular step.
Example Syntax
Here is an example demonstrating all three locations:
name: Example Workflow
<em># Workflow-level env</em>
env:
WORKFLOW_VAR: "This is a workflow variable"
on: [push]
jobs:
build:
runs-on: ubuntu-latest
<em># Job-level env</em>
env:
JOB_VAR: "This is a job variable"
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Use environment variables
<em># Step-level env</em>
env:
STEP_VAR: "This is a step variable"
run: |
echo "Workflow var: ${{ env.WORKFLOW_VAR }}"
echo "Job var: ${{ env.JOB_VAR }}"
echo "Step var: ${{ env.STEP_VAR }}"
Key Points
- The
envkeyword must be followed by a colon (:) and then indented key-value pairs for the variable names and their values. - Variables are accessed using the
${{ env.VARIABLE_NAME }}syntax within the workflow file itself, or using the standard shell syntax (e.g.,$VARIABLE_NAMEin bash,$env:VARIABLE_NAMEin PowerShell) within therunstep scripts. - Job-level variables take precedence over workflow-level variables if they have the same name, and step-level variables have the highest precedence.
- For sensitive information, you should use Gitea Secrets instead of environment variables in the YAML file. Secrets are also accessed via a context, like
${{ secrets.MY_SECRET }}.
The scope of env: defined directly under a - name: block (meaning at the step level) is strictly limited to that specific step’s execution environment [1].
Here’s exactly what that means:
- Available within the step: Any environment variables defined here can be accessed by the
runscript or theusesaction for that single step. - Not available in subsequent steps: As soon as that step finishes, those specific environment variables are removed from the environment and cannot be accessed by the next step in the job.
- Overrides higher levels: If a variable with the same name was defined at the job or workflow level, the step-level definition takes precedence for the duration of that single step’s execution [1].
Example of Step-Level Scope
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Step 1 with specific env
env:
TEMP_VAR: "I am only here for Step 1"
run: |
echo "Inside Step 1: $TEMP_VAR" # This works
- name: Step 2
run: |
echo "Inside Step 2: $TEMP_VAR" # This will output nothing (or an empty string)
If you need to make data generated or defined in one step available to subsequent steps,
you should use output parameters or environment files (using echo "::set-env name=VAR_NAME::value" in older runners
or echo "VAR_NAME=value" >> $GITHUB_ENV in newer runners/Gitea actions) instead of a simple env: block.
To make an env: variable available to all steps,
you can define it at either the workflow level or the job level.
1. Define at the Workflow Level (Recommended for all steps in all jobs)
Place the env: block at the top level of your YAML file, directly under the name: or on: keywords. Variables defined here are available to every single job and step in the entire workflow.
name: Example Workflow
env:
<em># This variable is available to all jobs and all steps</em>
GLOBAL_VAR: "I am everywhere"
ANOTHER_VAR: "Hello World"
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Step 1 can use global var
run: echo "Step 1: $GLOBAL_VAR"
- name: Step 2 can also use global var
run: echo "Step 2: $GLOBAL_VAR"
2. Define at the Job Level (Recommended for all steps within a specific job)
Place the env: block directly under a specific job ID (e.g., under build:).
Variables defined here are available to all steps within that specific job, but not to other jobs in the workflow.
name: Example Workflow
on: [push]
jobs:
build:
runs-on: ubuntu-latest
<em># This variable is available to all steps within the 'build' job</em>
env:
JOB_VAR: "I am only in the build job"
steps:
- name: Step 1 in build job
run: echo "Step 1: $JOB_VAR"
- name: Step 2 in build job
run: echo "Step 2: $JOB_VAR"
deploy:
runs-on: ubuntu-latest
steps:
- name: Step 1 in deploy job
<em># This will fail or be empty because JOB_VAR is not in scope</em>
run: echo "Step 1: $JOB_VAR"
Accessing the Variables
Within a run command using a shell (like bash on Linux/macOS or PowerShell on Windows),
you can typically access the variables using the standard shell syntax (e.g., $GLOBAL_VAR or %GLOBAL_VAR%).
For use outside of a run command (e.g., in conditional statements or other parts of the YAML structure),
use the expression syntax ${{ env.VARIABLE_NAME }}.
Both $GITHUB_OUTPUT and $GITHUB_ENV are valid and serve distinct purposes in GitHub Actions workflows.
$GITHUB_ENV:
- Used to set environment variables that are available to subsequent steps within the same job.
- Changes made to
$GITHUB_ENVin one step will not be accessible in other jobs in the workflow. - Example:
echo "MY_VARIABLE=my_value" >> $GITHUB_ENV
$GITHUB_OUTPUT:
- Used to set job outputs, which allow you to pass data between different jobs within the same workflow.
- To use
$GITHUB_OUTPUT, the step generating the output must have anid, and the job must define the output in itsoutputsblock. - The consuming job must use the
needskeyword to depend on the job that produces the output. - Example:
echo "my_output_name=output_value" >> $GITHUB_OUTPUT
In summary:
- Use
$GITHUB_ENVwhen you need to share data between steps within a single job. - Use
$GITHUB_OUTPUTwhen you need to share data between different jobs in a workflow.
