Skip to content

CI/CD

CI/CD #1066

Workflow file for this run

name: CI/CD
on:
push:
branches: ['main']
pull_request:
branches: ['main']
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
inputs:
release:
description: Create release?
required: false
type: boolean
version:
description: New version to release
required: false
type: string
jobs:
dependabot:
name: Auto-merge dependabot PR
if: github.event_name == 'pull_request' && github.event.sender.login == 'dependabot[bot]'
runs-on: ubuntu-latest
concurrency:
group: dependabot-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
steps:
- name: Approve and Auto-merge
run: |
gh pr review --approve "${{ github.event.pull_request.html_url }}"
gh pr merge --auto --squash "${{ github.event.pull_request.html_url }}"
env:
GITHUB_TOKEN: ${{ secrets.COMMIT_TOKEN }}
ci:
name: Check requirements
runs-on: ubuntu-latest
outputs:
run: ${{ github.event_name != 'push' }}
release: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release == 'true' }}
check_latest: ${{ steps.swift-org.outputs.check_latest }}
update_latest: ${{ github.ref_name == github.event.repository.default_branch && steps.swift-org.outputs.update_latest == 'true' }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: npm
- name: Cache dependencies
uses: actions/[email protected]
with:
key: node-${{ github.ref }}
path: node_modules
- name: Setup npm pacakges
run: npm install --legacy-peer-deps
env:
SETUPSWIFT_SWIFTORG_METADATA: ${{ github.event_name == 'schedule' && '{"commit":"HEAD"}' }}
- name: Check latest swift.org
id: swift-org
uses: actions/github-script@v7
with:
script: |
const hook = require('.github/utils/update_metadata.js');
const {stdout} = await exec.getExecOutput('git', ['rev-parse', 'HEAD'], {cwd: 'swiftorg'});
const oldCommit = (await hook.currentData()).commit;
const newCommit = stdout.trim();
core.setOutput('check_latest', newCommit);
core.setOutput('update_latest', newCommit != oldCommit);
analyze:
name: Run CodeQL analysis
if: github.event_name != 'workflow_dispatch'
needs: ci
runs-on: ubuntu-latest
concurrency:
group: analyze-${{ github.ref }}
cancel-in-progress: true
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
unit-test:
name: Run unit tests
needs: ci
runs-on: ubuntu-latest
concurrency:
group: unit-test-${{ github.ref }}
cancel-in-progress: true
env:
SETUPSWIFT_SWIFTORG_METADATA: ${{ format('{{"commit":"{0}"}}', needs.ci.outputs.check_latest) }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: npm
- name: Cache dependencies
uses: actions/[email protected]
with:
key: node-${{ github.ref }}
path: node_modules
- name: Setup and Run unit tests
run: |
npm install --legacy-peer-deps
npm run lint
npm run test
- name: Codecov upload
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: ${{ github.event_name == 'push' }}
integration-test:
name: Integrate Swift ${{ matrix.swift }} on ${{ matrix.os }} with development ${{ matrix.development }}
if: needs.ci.outputs.run == 'true'
needs: ci
runs-on: ${{ matrix.os }}
concurrency:
group: integration-test-${{ github.ref }}-${{ matrix.os }}-${{ matrix.swift }}-${{ matrix.development }}
cancel-in-progress: true
env:
SETUPSWIFT_SWIFTORG_METADATA: ${{ format('{{"commit":"{0}"}}', needs.ci.outputs.check_latest) }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
swift: ['latest']
development: [false, true]
include:
- os: macos-latest
swift: '5.0.0'
development: false
- os: macos-13
swift: 'latest'
development: false
- os: ubuntu-latest
swift: '5.3.0'
development: false
- os: windows-latest
swift: '5.3'
development: false
- os: ubuntu-22.04
swift: ${{ fromJSON(vars.SETUPSWIFT_CUSTOM_TOOLCHAINS).ubuntu2204 }}
development: true
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: npm
- name: Cache dependencies
uses: actions/[email protected]
with:
key: node-${{ github.ref }}
path: node_modules
- name: Setup and Build
run: |
npm install --legacy-peer-deps
npm run build
npm run package
- name: Run
id: setup-swift
uses: ./
with:
swift-version: ${{ matrix.swift }}
development: ${{ matrix.development }}
check-latest: ${{ needs.ci.outputs.check_latest }}
cache-snapshot: ${{ !matrix.development }}
- name: Verify Swift version in macos
if: runner.os == 'macOS'
run: xcrun --toolchain ${{ env.TOOLCHAINS || '""' }} swift --version | grep ${{ steps.setup-swift.outputs.swift-version }} || exit 1
- name: Verify Swift version
run: swift --version | grep ${{ steps.setup-swift.outputs.swift-version }} || exit 1
dry-run:
name: Check action with dry run
if: needs.ci.outputs.run == 'true'
needs: ci
runs-on: ubuntu-latest
continue-on-error: true
concurrency:
group: dry-run-${{ github.ref }}
cancel-in-progress: true
env:
SETUPSWIFT_SWIFTORG_METADATA: ${{ format('{{"commit":"{0}"}}', needs.ci.outputs.check_latest) }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: npm
- name: Cache dependencies
uses: actions/[email protected]
with:
key: node-${{ github.ref }}
path: node_modules
- name: Setup and Build
run: |
npm install --legacy-peer-deps
npm run build
npm run package
- name: Run
id: setup-swift
uses: ./
with:
check-latest: ${{ needs.ci.outputs.check_latest }}
dry-run: true
- name: Verify Swift version
uses: addnab/docker-run-action@v3
with:
image: swift:${{ fromJSON(steps.setup-swift.outputs.toolchain).docker }}
run: swift --version | grep ${{ steps.setup-swift.outputs.swift-version }} || exit 1
e2e-test:
name: End-to-end test latest Swift on ${{ matrix.os }}
if: needs.ci.outputs.run == 'true'
needs: ci
runs-on: ${{ matrix.os }}
concurrency:
group: e2e-test-${{ github.ref }}-${{ matrix.os }}
cancel-in-progress: true
env:
COMPOSITE: ./.ref-download-test
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Setup wrapper composite action at ${{ env.COMPOSITE }}
uses: actions/github-script@v7
with:
script: |
const path = require('path');
const fs = require('fs/promises');
const composite = '${{ env.COMPOSITE }}';
const repo = '${{ github.event.pull_request.head.repo.full_name || github.repository }}';
const branch = '${{ github.head_ref || github.ref_name }}';
const action = {
outputs: {
'swift-version': {
value: '$' + `{{ steps.run.outputs.swift-version }}`
}
},
runs: {
using: 'composite',
steps: [
{
name: 'Cleanup',
uses: `actions/github-script@${{ github.action_ref }}`,
with: {
script: `await io.rmRF('${composite}')`
}
},
{
name: `Run ${repo}@${branch}`,
id: 'run',
uses: `${repo}@${branch}`,
with: {
'swift-version': 'latest',
'check-latest': '${{ needs.ci.outputs.check_latest }}'
}
}
]
}
};
const content = JSON.stringify(action);
core.debug(`Writing action:\n${content}\n`);
await io.mkdirP(composite);
await fs.writeFile(path.join(composite, 'action.yml'), content);
- name: Run composite action ${{ env.COMPOSITE }}
id: setup-swift
uses: ./.ref-download-test
- name: Cleanup
if: always()
uses: actions/github-script@v7
continue-on-error: true
with:
script: await io.rmRF('${{ env.COMPOSITE }}');
- name: Verify Swift version in macos
if: runner.os == 'macOS'
run: xcrun --toolchain ${{ env.TOOLCHAINS || '""' }} swift --version | grep ${{ steps.setup-swift.outputs.swift-version }} || exit 1
- name: Verify Swift version
run: swift --version | grep ${{ steps.setup-swift.outputs.swift-version }} || exit 1
- name: Test Swift package
run: |
swift package init --type library --name SetupLib
swift build --build-tests
swift test
pages:
name: Publish metadata to GitHub Pages
if: |
always() && needs.ci.outputs.update_latest == 'true' &&
(needs.analyze.result == 'success' || needs.analyze.result == 'skipped') &&
(needs.unit-test.result == 'success' || needs.unit-test.result == 'skipped') &&
(needs.integration-test.result == 'success' || needs.integration-test.result == 'skipped') &&
(needs.dry-run.result == 'success' || needs.dry-run.result == 'skipped') &&
(needs.e2e-test.result == 'success' || needs.e2e-test.result == 'skipped')
needs: [ci, analyze, unit-test, integration-test, dry-run, e2e-test]
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
concurrency:
group: pages-update
cancel-in-progress: true
permissions:
id-token: write
pages: write
runs-on: ubuntu-latest
env:
SETUPSWIFT_SWIFTORG_METADATA: ${{ format('{{"commit":"{0}"}}', needs.ci.outputs.check_latest) }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: npm
- name: Cache dependencies
uses: actions/[email protected]
with:
key: node-${{ github.ref }}
path: node_modules
- name: Setup npm pacakges
run: npm install --legacy-peer-deps
- name: Generate swift.org metadata
id: swiftorg-metadata
uses: actions/github-script@v7
with:
script: |
const hook = require('.github/utils/update_metadata.js');
await hook.update();
return true;
- name: Upload artifact
if: steps.swiftorg-metadata.outputs.result == 'true'
uses: actions/upload-pages-artifact@v3
with:
path: pages
- name: Deploy to GitHub Pages
if: steps.swiftorg-metadata.outputs.result == 'true'
id: deployment
uses: actions/deploy-pages@v4
cd:
name: Create release
if: |
always() && needs.ci.outputs.release == 'true' &&
(needs.analyze.result == 'success' || needs.analyze.result == 'skipped') &&
(needs.unit-test.result == 'success' || needs.unit-test.result == 'skipped') &&
(needs.integration-test.result == 'success' || needs.integration-test.result == 'skipped') &&
(needs.dry-run.result == 'success' || needs.dry-run.result == 'skipped') &&
(needs.e2e-test.result == 'success' || needs.e2e-test.result == 'skipped')
needs: [ci, analyze, unit-test, integration-test, dry-run, e2e-test]
runs-on: ubuntu-latest
concurrency:
group: cd-${{ github.ref }}
cancel-in-progress: true
env:
SETUPSWIFT_SWIFTORG_METADATA: ${{ format('{{"commit":"{0}"}}', needs.ci.outputs.check_latest) }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-tags: true
token: ${{ secrets.COMMIT_TOKEN }}
- name: Import GPG
uses: crazy-max/[email protected]
with:
gpg_private_key: ${{ secrets.COMMIT_SIGN_KEY }}
passphrase: ${{ secrets.COMMIT_SIGN_KEY_PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true
git_tag_gpgsign: true
git_push_gpgsign: if-asked
- name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: npm
- name: Cache dependencies
uses: actions/[email protected]
with:
key: node-${{ github.ref }}
path: node_modules
- name: Setup npm pacakges
run: npm install --legacy-peer-deps
- name: Generate changelog
id: changelog
uses: TriPSs/conventional-changelog-action@v5
with:
github-token: ${{ secrets.COMMIT_TOKEN }}
git-message: 'chore(CHANGELOG): update for {version}'
git-user-name: swiftylab-ci
git-user-email: [email protected]
release-count: 0
version-file: ./package.json
version-path: version
fallback-version: ${{ inputs.version || '1.0.0' }}
config-file-path: .github/changelog/config.js
pre-commit: .github/changelog/pre_commit_hook.js
pre-changelog-generation: .github/changelog/pre_changelog_hook.js
create-summary: true
env:
VERSION: ${{ inputs.version }}
NODE_PATH: ${{ github.workspace }}/node_modules
- name: Update latest major version tag
uses: actions/github-script@v7
with:
github-token: ${{ secrets.COMMIT_TOKEN }}
script: |
const semver = require('semver');
const fs = require('fs/promises');
const package = JSON.parse(await fs.readFile('package.json', 'utf8'));
const version = `v${semver.coerce(package.version).major}`;
await exec.exec('git', ['push', '--signed=if-asked', 'origin', `:refs/tags/${version}`]);
await exec.exec('git', ['tag', '-sfa', version, '-m', version]);
await exec.exec('git', ['push', '--signed=if-asked', 'origin', '--tags']);
return true;
- name: Update latest tag
run: |
git push --signed=if-asked origin :refs/tags/latest
git tag -sfa latest -m latest
git push --signed=if-asked origin --tags
- name: Create GitHub release
uses: ncipollo/release-action@v1
with:
token: ${{ github.token }}
tag: ${{ steps.changelog.outputs.tag }}
body: ${{ steps.changelog.outputs.changelog }}