diff --git a/.github/workflows/app-build-verify.yml b/.github/workflows/app-build-verify.yml index 76bef730..b02e6751 100644 --- a/.github/workflows/app-build-verify.yml +++ b/.github/workflows/app-build-verify.yml @@ -32,6 +32,10 @@ on: description: "The target format for the app, e.g. appimage, xcode, app, etc. Leave blank all supported formats." default: "" type: string + briefcase-artifact-name: + description: "Name of the GitHub artifact for the Briefcase package to install." + default: "" + type: string workflow-repo: # Only needed for PRs in other repos wanting to test new workflow changes before they are merged. # These inputs should not be specified by another repo on their main branch. @@ -127,7 +131,8 @@ jobs: if: endsWith(inputs.repository, 'briefcase') uses: actions/download-artifact@v4.1.7 with: - name: packages-briefcase + pattern: ${{ format('{0}*', inputs.briefcase-artifact-name) }} + merge-multiple: true path: dist - name: Install Briefcase Artefacts diff --git a/.github/workflows/app-create-verify.yml b/.github/workflows/app-create-verify.yml index e88166df..45e06af1 100644 --- a/.github/workflows/app-create-verify.yml +++ b/.github/workflows/app-create-verify.yml @@ -19,6 +19,14 @@ on: description: "Framework to use to build the App, e.g. toga." required: true type: string + repository: + description: "GitHub repository to checkout; defaults to repo running this workflow." + default: ${{ github.repository }} + type: string + briefcase-artifact-name: + description: "Name of the GitHub artifact for the Briefcase package to install." + default: "" + type: string workflow-repo: # Only needed for PRs in other repos wanting to test new workflow changes before they are merged. # These inputs should not be specified by another repo on their main branch. @@ -44,10 +52,10 @@ jobs: timeout-minutes: 30 steps: - - name: Checkout ${{ github.repository }} + - name: Checkout ${{ inputs.repository }} uses: actions/checkout@v4.1.6 with: - repository: ${{ github.repository }} + repository: ${{ inputs.repository }} fetch-depth: 0 - name: Checkout ${{ inputs.workflow-repo }}${{ inputs.workflow-repo-ref && format('@{0}', inputs.workflow-repo-ref) || '' }} @@ -79,10 +87,10 @@ jobs: - name: Get Briefcase Package # Briefcase will build and package itself in a previous step in its CI - if: endsWith(github.repository, 'briefcase') + if: endsWith(inputs.repository, 'briefcase') uses: actions/download-artifact@v4.1.7 with: - name: packages-briefcase + name: ${{ inputs.briefcase-artifact-name }} path: dist - name: Install Briefcase Artefact diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c6733bc..8220bb89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: - main concurrency: - group: ${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true defaults: @@ -157,42 +157,52 @@ jobs: pre-commit-source: ./core[dev] test-package-python: - name: Create Package + name: Package Briefcase needs: pre-commit uses: ./.github/workflows/python-package-create.yml with: - repository: beeware/${{ matrix.repo }} - tox-source: ${{ matrix.tox-source }} - tox-factors: ${{ matrix.tox-factors }} - distribution-path: ${{ matrix.dist-path }} + repository: beeware/${{ matrix.repo || matrix.name }} build-subdirectory: ${{ matrix.build-subdir }} strategy: fail-fast: false matrix: - repo: [ briefcase, gbulb, rubicon-objc, toga ] + name: + - beeware + - briefcase-automation + - gbulb + - rubicon-objc + - toga-core + - toga-android + - toga-chart + - travertino include: - - tox-source: .[dev] - - dist-path: dist - - repo: briefcase - tox-source: .[dev] - tox-factors: -with-automation - dist-path: dist - - repo: gbulb - tox-source: tox - dist-path: dist - - repo: toga - tox-source: ./core[dev] - dist-path: "*/dist/*" + - name: briefcase-automation + repo: briefcase + build-subdir: automation + - name: toga-core + repo: toga build-subdir: core + - name: toga-android + repo: toga + build-subdir: android + + test-package-briefcase: + name: Create Package + needs: pre-commit + uses: ./.github/workflows/python-package-create.yml + with: + repository: beeware/briefcase test-verify-projects-briefcase: name: Verify Project - needs: [ pre-commit, test-package-python ] + needs: [ pre-commit, test-package-briefcase ] uses: ./.github/workflows/app-create-verify.yml with: python-version: "3.10" # must match system python for ubuntu version + repository: beeware/briefcase runner-os: ${{ matrix.runner-os }} framework: ${{ matrix.framework }} + briefcase-artifact-name: ${{ needs.test-package-briefcase.outputs.artifact-name }} strategy: fail-fast: false matrix: @@ -201,13 +211,14 @@ jobs: test-verify-apps-briefcase: name: Verify Briefcase - needs: [ pre-commit, test-package-python ] + needs: [ pre-commit, test-package-python, test-package-briefcase ] uses: ./.github/workflows/app-build-verify.yml with: python-version: "3.10" # must match system python for ubuntu version repository: beeware/briefcase runner-os: ${{ matrix.runner-os }} framework: ${{ matrix.framework }} + briefcase-artifact-name: ${{ needs.test-package-briefcase.outputs.artifact-basename }} strategy: fail-fast: false matrix: diff --git a/.github/workflows/python-package-create.yml b/.github/workflows/python-package-create.yml index 5147069c..86c744f9 100644 --- a/.github/workflows/python-package-create.yml +++ b/.github/workflows/python-package-create.yml @@ -1,50 +1,36 @@ name: Create Python Package ####### -# Creates a Python package via `tox -e package` and uploads it as an artifact named 'packages-'. +# Creates a Python package for an arbitrary repository and subdirectory with optional attestation. ####### on: workflow_call: inputs: - python-version: - description: "Python version to use; defaults to latest Python release." - default: "3.X" - type: string repository: description: "GitHub repository to checkout; defaults to repo running this workflow." default: ${{ github.repository }} type: string - tox-source: - description: "The arguments for `pip install` to install tox; use ./path/to/package[dev] for the repo's pinned version." - default: ".[dev]" - type: string - tox-factors: - description: "The tox factors to append to the package command." - default: "" - type: string build-subdirectory: description: "The subdirectory to build as a wheel." default: "" type: string - distribution-path: - description: "Relative filepath to distribution(s); e.g. */dist/*" - default: "dist" - type: string - runner-os: - description: "Runner OS to use to run tox; defaults to ubuntu-latest" - default: "ubuntu-latest" + attest: + description: "Create GitHub provenance attestation for the package." + default: "false" type: string outputs: artifact-name: - description: > - Name of the uploaded artifact; use for artifact retrieval. - Note that if a `build-subdirectory` is specified, this value will be the "base" of the artifact name. - For instance, if the `core` subdirectory of Toga is being built, then this value will be `packages-toga` - but the name of the uploaded artifact will be `packages-toga-core`. - Therefore, when a `build-subdirectory` is used with this workflow, the `pattern` input for the - `actions\download-artifact` should be used to specify `${ needs.package.outputs.artifact-name }-*`. + description: "Name of the uploaded artifact; use for artifact retrieval." value: ${{ jobs.package.outputs.artifact-name }} + artifact-basename: + description: > + The base name for a group of related package artifacts. + When several packages are created from a single repo, such as for Toga, a separate artifact + will be created for each package, e.g. Packages-toga-core, Packages-toga-android, etc. + Therefore, the base name for these artifacts is Packages-toga. This output allows the caller + to retrieve all of these related artifacts with one call to actions/download-artifact. + value: ${{ jobs.package.outputs.artifact-basename }} env: FORCE_COLOR: "1" @@ -52,14 +38,24 @@ env: jobs: package: name: Create Python Package - runs-on: ${{ inputs.runner-os }} + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + attestations: write outputs: - artifact-name: packages-${{ steps.package.outputs.name }} + artifact-name: ${{ steps.package.outputs.artifact-name }} + artifact-basename: ${{ steps.artifact.outputs.basename }} steps: - - name: Determine Package Name - id: package - run: echo "name=$(basename '${{ inputs.repository }}')" >> ${GITHUB_OUTPUT} + - name: Determine Artifact Differentiators + id: config + env: + REPO: ${{ inputs.repository }} + DIFFERENTIATOR: ${{ inputs.build-subdirectory && format('-{0}', inputs.build-subdirectory) || '' }} + run: | + echo "repo-name=$(basename "${REPO}")" | tee -a ${GITHUB_OUTPUT} + echo "differentiator=${DIFFERENTIATOR}" | tee -a ${GITHUB_OUTPUT} - name: Checkout uses: actions/checkout@v4.1.6 @@ -67,32 +63,18 @@ jobs: repository: ${{ inputs.repository }} fetch-depth: 0 # Fetch all refs so setuptools_scm can generate the correct version number - - name: Setup Python - uses: actions/setup-python@v5.1.0 + - name: Build Package & Upload Artifact + id: package + uses: hynek/build-and-inspect-python-package@v2.6.0 with: - python-version: ${{ inputs.python-version }} - cache: pip - cache-dependency-path: | - **/setup.cfg - **/pyproject.toml - - - name: Update pip - run: python -m pip install -U pip - - - name: Install tox - run: python -m pip install ${{ inputs.tox-source }} + path: ${{ inputs.build-subdirectory || '.' }} + upload-name-suffix: ${{ format('-{0}{1}', steps.config.outputs.repo-name, steps.config.outputs.differentiator) }} + attest-build-provenance-github: ${{ inputs.attest }} - - name: Build Wheels - if: inputs.build-subdirectory == '' - run: tox -e package${{ inputs.tox-factors }} - - - name: Build Wheels from Subdirectory - if: inputs.build-subdirectory != '' - run: tox -e package${{ inputs.tox-factors }} -- ${{ inputs.build-subdirectory }} - - - name: Upload Package - uses: actions/upload-artifact@v4.3.3 - with: - name: packages-${{ steps.package.outputs.name }}${{ inputs.build-subdirectory && format('-{0}', inputs.build-subdirectory) || '' }} - path: ${{ inputs.distribution-path }} - if-no-files-found: error + - name: Determine Artifact Basename + id: artifact + env: + BASENAME: ${{ steps.package.outputs.artifact-name }} + run: | + # trim the differentiator to generate the artifact's basename + echo "basename=${BASENAME%-${{ steps.config.outputs.differentiator }}}" | tee -a ${GITHUB_OUTPUT}