Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ indent_size = 2
[*.json]
indent_size = 2

[*.yml]
indent_size = 2

# Shell scripts
[*.sh]
end_of_line = lf
Expand Down
178 changes: 178 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
name: Build

on:
push:
branches:
- 'main'
- 'release/**'
- 'force-ci/**'
- 'xpf/**'
- '!release/latest'
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: build-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_NOLOGO: 1

jobs:

linux:
name: Linux
runs-on: ubuntu-24.04

steps:
- &step-checkout
name: Checkout
uses: actions/checkout@v7
with:
submodules: recursive

- &step-dotnet
name: Install .NET
uses: actions/setup-dotnet@v6
with:
dotnet-version: 8.0.x
global-json-file: global.json
Comment thread
maxkatz6 marked this conversation as resolved.
Comment on lines +43 to +44

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason for both dotnet-version and global-json-file?
We only need to install latest SDK we need. Any extra runtimes are already preinstalled, like .NET 8 runtime.


- name: Install Workloads
run: dotnet workload install android macos wasm-tools

- name: Run Build
run: |
dotnet --info
printenv
./build.sh --target CiLinux --configuration=Release

macos:
name: macOS
runs-on: macos-26
env:
DEVELOPER_DIR: /Applications/Xcode_26.6.app/Contents/Developer

steps:
- *step-checkout

- *step-dotnet

- name: Install Workloads
run: dotnet workload install android ios tvos maccatalyst macos wasm-tools

- name: Run Build
run: |
dotnet --info
printenv
./build.sh --target CiMacOS --configuration Release

- name: Publish Native Library
uses: actions/upload-artifact@v7
with:
name: native-macos
path: artifacts/native/Release/

- name: Publish NuGet Packages
uses: actions/upload-artifact@v7
with:
name: nuget-macos
path: artifacts/nuget

- name: Publish SBOM
uses: actions/upload-artifact@v7
with:
name: sbom-macos
path: artifacts/sbom

windows:
name: Windows
runs-on: windows-2025

steps:
- *step-checkout

- *step-dotnet

- name: Install Workloads
run: dotnet workload install android ios tvos maccatalyst macos wasm-tools

- name: Run Build
run: ./build.cmd --target CiWindows --configuration Release

- name: Publish NuGet Packages
uses: actions/upload-artifact@v7
with:
name: nuget-windows
path: artifacts/nuget

- name: Publish SBOM
uses: actions/upload-artifact@v7
with:
name: sbom-windows
path: artifacts/sbom

# Only release/x.y.z branches (with an optional prerelease suffix) are releasable, not release/x.y ones.
# Expressions have no regex support, so a small job classifies the branch instead.
branch-info:
name: Branch Info
runs-on: ubuntu-24.04
outputs:
is-release: ${{ steps.classify.outputs.is-release }}
steps:
- name: Classify Branch
id: classify
env:
REF: ${{ github.ref }}
run: |
if [[ "$REF" =~ ^refs/heads/release/[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
is_release=true
else
is_release=false
fi
echo "Ref: $REF, is release: $is_release"
echo "is-release=$is_release" >> "$GITHUB_OUTPUT"

# Note: pull requests are published by publish-nuget-pr.yml instead, which runs once this workflow completes.

publish-nightly:
name: Publish Nightly NuGet Packages
needs: [linux, windows, macos, branch-info]
# Everything except pull requests and release/x.y.z branches (release/x.y ones are nightlies too).
if: >-
github.event_name != 'pull_request'
&& needs.branch-info.outputs.is-release != 'true'
&& vars.NIGHTLY_FEED_UPLOAD_URL != ''
uses: ./.github/workflows/publish-nuget-shared.yml
with:
feed-url: ${{ vars.NIGHTLY_FEED_UPLOAD_URL }}
secrets:
api-key: ${{ secrets.NIGHTLY_FEED_API_KEY }}

# Pushes to release/x.y.z build automatically, but publishing waits for a manual approval of the "release" environment
# (configured with required reviewers in the repository settings). Only this run's packages can be published.
approve-release:
name: Approve Release NuGet Publishing
needs: [linux, windows, macos, branch-info]
if: >-
github.event_name != 'pull_request'
&& needs.branch-info.outputs.is-release == 'true'
runs-on: ubuntu-24.04
environment: release
steps:
- name: Approved
run: echo "Release publishing approved for run $GITHUB_RUN_ID"

publish-release:
name: Publish Release NuGet Packages
needs: approve-release
uses: ./.github/workflows/publish-nuget-shared.yml
with:
feed-url: ${{ vars.RELEASE_MANAGER_UPLOAD_URL }}
secrets:
api-key: ${{ secrets.RELEASE_MANAGER_API_KEY }}
Comment on lines +165 to +178

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's wrong.
approve-release has environment: release on it, so it has to be approved.
But secrets.RELEASE_MANAGER_API_KEY secret is not protected by this environment, and would have to be defined on the whole repository, not just environment.

Instead, RELEASE_MANAGER_API_KEY should be only defined on the release env, and only be accessed from CI jobs marked with environment: release (so publish-release needs to be marked).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approve-release is probably unnecessary in this case. publish-release needs to require an approve.

86 changes: 86 additions & 0 deletions .github/workflows/publish-nuget-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Publish PR NuGet Packages

# Publishes the packages built by the Build workflow for a pull request, including pull requests from forks,
# so that contributors can directly test their changes.
#
# This runs in the context of the main repository with access to secrets, while the packages were built
# from untrusted pull request code. That is accepted for the "all" feed only.
# NEVER check out or execute anything from the pull request here: only download the artifacts and push them.

on:
workflow_run:
workflows: [Build]
types: [completed]

permissions:
contents: read
actions: read

concurrency:
group: publish-pr-nuget-${{ github.event.workflow_run.event }}-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have concurrency defined on build, but not sure about nuget publish. It might end up with some packages published, and other not.

cancel-in-progress: true

jobs:
publish:
name: Publish PR NuGet Packages
if: >-
github.event.workflow_run.event == 'pull_request'
&& github.event.workflow_run.conclusion == 'success'
&& vars.ALL_FEED_UPLOAD_URL != ''
uses: ./.github/workflows/publish-nuget-shared.yml
with:
feed-url: ${{ vars.ALL_FEED_UPLOAD_URL }}
run-id: ${{ github.event.workflow_run.id }}
secrets:
api-key: ${{ secrets.ALL_FEED_API_KEY }}

comment:
name: Comment on Pull Request
needs: publish
runs-on: ubuntu-24.04
permissions:
pull-requests: write

steps:
- name: Post Package Version
uses: actions/github-script@v7
env:
HEAD_OWNER: ${{ github.event.workflow_run.head_repository.owner.login }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
VERSION: ${{ needs.publish.outputs.version }}
RUN_URL: ${{ github.event.workflow_run.html_url }}
FEED_URL: ${{ vars.ALL_FEED_DOWNLOAD_URL }}
with:
script: |
const { HEAD_OWNER, HEAD_BRANCH, HEAD_SHA, VERSION, RUN_URL, FEED_URL } = process.env;
const { owner, repo } = context.repo;

// The workflow_run payload doesn't list pull requests from forks, so look the pull request up
// from its head branch, and make sure it still points to the commit that was built.
const { data: pulls } = await github.rest.pulls.list({
owner, repo, state: 'open', head: `${HEAD_OWNER}:${HEAD_BRANCH}`,
});
const pr = pulls.find(p => p.head.sha === HEAD_SHA);
if (!pr) {
core.warning(`No open pull request found for ${HEAD_OWNER}:${HEAD_BRANCH} at ${HEAD_SHA}.`);
return;
}

const marker = '<!-- pr-nuget-bot -->';
const body =
`${marker}\n### NuGet packages\n\n` +
`The packages for this pull request have been published ([workflow run](${RUN_URL})):\n\n` +
`- Version: \`${VERSION}\`\n` +
`- Feed URL: ${FEED_URL}`;

// Update the existing comment (from a previous push) or create a new one.
const { data: comments } = await github.rest.issues.listComments({
owner, repo, issue_number: pr.number, per_page: 100,
});
const existing = comments.find(c => c.user?.login === 'github-actions[bot]' && c.body?.startsWith(marker));
if (existing) {
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
} else {
await github.rest.issues.createComment({ owner, repo, issue_number: pr.number, body });
}
72 changes: 72 additions & 0 deletions .github/workflows/publish-nuget-shared.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Publish NuGet Packages

# Reusable workflow: downloads the NuGet packages built by the Build workflow and pushes them to a feed.

on:
workflow_call:
inputs:
feed-url:
description: URL of the NuGet feed to push the packages to.
required: true
type: string
run-id:
description: ID of the Build workflow run to take the packages from. Defaults to the current run.
required: false
type: number
secrets:
api-key:
description: API key of the NuGet feed.
required: true
outputs:
version:
description: Version of the published packages.
value: ${{ jobs.publish.outputs.version }}

jobs:
publish:
name: Publish NuGet Packages
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.version.outputs.version }}

steps:
- name: Install .NET
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x

# A token is only needed when downloading from another run.
- name: Download Windows NuGet Packages
uses: actions/download-artifact@v7
with:
name: nuget-windows
path: nuget-windows
run-id: ${{ inputs.run-id || github.run_id }}
github-token: ${{ (inputs.run-id && github.token) || '' }}

- name: Download macOS NuGet Packages
uses: actions/download-artifact@v7
with:
name: nuget-macos
path: nuget-macos
run-id: ${{ inputs.run-id || github.run_id }}
github-token: ${{ (inputs.run-id && github.token) || '' }}

- name: Get Package Version
id: version
run: |
package=$(basename nuget-windows/Avalonia.[0-9]*.nupkg)
version=${package#Avalonia.}
version=${version%.nupkg}
if [[ ! "$version" =~ ^[0-9A-Za-z.+-]+$ ]]; then
echo "::error::Could not determine the package version from '$package'."
exit 1
fi
echo "Package version: $version"
echo "version=$version" >> "$GITHUB_OUTPUT"

- name: Push to Feed
run: |
dotnet nuget push "nuget-windows/*.nupkg" "nuget-macos/Avalonia.Native.*.nupkg" \
--source "${{ inputs.feed-url }}" \
--api-key "${{ secrets.api-key }}"
12 changes: 5 additions & 7 deletions .nuke/build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,19 @@
"type": "string",
"enum": [
"BuildToNuGetCache",
"CiAzureLinux",
"CiAzureOSX",
"CiAzureWindows",
"CiLinux",
"CiMacOS",
"CiWindows",
"Clean",
"Compile",
"CompileNative",
"CreateIntermediateNugetPackages",
"CreateNugetPackages",
"CreateSbom",
"DownloadApiBaselinePackages",
"EmbedSbom",
"GenerateUnicodeData",
"InitDnx",
"OutputApiDiff",
"OutputVersion",
"Package",
"RunCoreLibsTests",
"RunHtmlPreviewerTests",
Expand All @@ -47,8 +46,7 @@
"RunTests",
"RunToolsTests",
"ValidateApiDiff",
"VerifyXamlCompilation",
"ZipFiles"
"VerifyXamlCompilation"
]
},
"Verbosity": {
Expand Down
3 changes: 0 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,4 @@
<PackageVersion Include="xunit.v3.extensibility.core" Version="3.2.2" />
<PackageVersion Include="xunit.v3.mtp-v2" Version="3.2.2" />
</ItemGroup>
<ItemGroup>
<GlobalPackageReference Include="Microsoft.VisualStudio.SlnGen" Version="8.5.17" PrivateAssets="all" />
</ItemGroup>
</Project>
Loading
Loading