Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

init: add shared workflows and tools #1

Merged
merged 6 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Snapcrafters CI

This repository contains common actions and tools used throughout the Snapcrafters
[organisation](https://github.com/snapcrafters) for the testing and delivery of our snaps.

## Snapcrafters Actions

The actions in this repo are all used during the build, test and release of our snaps. Each of them
listed below has it's own README

- [snapcrafters/ci/call-for-testing](call-for-testing/README.md)
- [snapcrafters/ci/get-architectures](get-architectures/README.md)
- [snapcrafters/ci/get-screenshots](get-screenshots/README.md)
- [snapcrafters/ci/promote-to-stable](promote-to-stable/README.md)
- [snapcrafters/ci/release-to-candidate](release-to-candidate/README.md)
- [snapcrafters/ci/sync-version](sync-version/README.md)
- [snapcrafters/ci/test-snap-build](test-snap-build/README.md)

### Usage

You can see examples of these actions in use in the following repos:

- [signal-desktop](https://github.com/snapcrafters/signal-desktop/main/.github/workflows)
- [mattermost-desktop](https://github.com/snapcrafters/mattermost-desktop/main/.github/workflows)
- [discord](https://github.com/snapcrafters/discord/main/.github/workflows)
75 changes: 75 additions & 0 deletions call-for-testing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# snapcrafters/ci/call-for-testing

Automatically creates a templated call for testing as a Github issue, containing the details of
newly released revisions and instructions on how to test and promote them.

## Usage

### Use in combination with `snapcrafters/ci/release-to-candidate`

In this mode, the action will look for an artifact uploaded by the
`snapcrafters/ci/release-to-candidate` action that contains a manifest detailing the exact
revisions that were uploaded, and use those to populate the call for testing template.

```yaml
jobs:
release:
name: 🚢 Release to latest/candidate
runs-on: ubuntu-latest
steps:
- name: 🚢 Release to latest/candidate
uses: snapcrafters/ci/release-to-candidate@main
with:
architecture: arm64
launchpad-token: ${{ secrets.LAUNCHPAD_TOKEN }}
store-token: ${{ secrets.STORE_TOKEN }}

call-for-testing:
name: 📣 Create call for testing
needs: release
runs-on: ubuntu-latest
steps:
- name: 📣 Create call for testing
uses: snapcrafters/ci/call-for-testing@main
with:
architectures: "amd64 arm64"
github-token: ${{ secrets.GITHUB_TOKEN }}
```

### Use standalone - `store-token` required

In this mode, the action will use the store token to fetch the latest revision on the specified
channel (`candidate` by default) for each architecture and populate the call for testing with those
revisions.

```yaml
jobs:
call-for-testing:
name: 📣 Create call for testing
runs-on: ubuntu-latest
steps:
- name: 📣 Create call for testing
uses: snapcrafters/ci/call-for-testing@main
with:
architectures: "amd64 arm64"
github-token: ${{ secrets.GITHUB_TOKEN }}
store-token: ${{ secrets.STORE_TOKEN }}
```

## API

### Inputs

| Key | Description | Required | Default |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: | :---------------- |
| `architectures` | The architectures that the snap supports. | Y | `amd64 arm64` |
jnsgruk marked this conversation as resolved.
Show resolved Hide resolved
| `ci-repo` | The repo to fetch tools/templates from. Only for debugging. | N | `snapcrafters/ci` |
| `channel` | The channel to create the call for testing for. | N | `candidate` |
| `github-token` | A token with permissions to create issues on the repository. | Y | |
| `store-token` | A token with permissions to query the specified channel in the Snap Store. Only required if the revisions to test are not passed to the workflow by the `release-to-candidate` workflow | N | |

### Outputs

| Key | Description | Example |
| -------------- | ------------------------------------------------- | ------- |
| `issue-number` | The issue number containing the call for testing. | `12` |
113 changes: 113 additions & 0 deletions call-for-testing/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
name: Create call for testing
description: Create a call for testing for a given snap repository
author: Snapcrafters
branding:
icon: message-circle
color: orange

inputs:
architectures:
description: "The architectures to build the snap for"
required: true
ci-repo:
description: "The repo to fetch tools/templates from. Only for debugging"
default: "snapcrafters/ci"
required: false
channel:
description: "The channel to publish the snap to"
default: "candidate"
required: false
github-token:
description: "A token with permissions to create issues on the repository"
required: true
store-token:
description: "A token with permissions to upload to the specified channel"
required: false

outputs:
issue-number:
description: "The issue number containing the call for testing"
value: ${{ steps.issue.outputs.number }}

runs:
using: composite
steps:
- name: Checkout the source
uses: actions/checkout@v4

- name: Download manifest files
continue-on-error: true
uses: actions/download-artifact@v3
with:
name: "manifests"

- name: Setup snapcraft
shell: bash
run: |
sudo snap install snapcraft --classic

- name: Write the arch/rev table
shell: bash
id: build
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ inputs.store-token }}
SNAP_NAME: ${{ github.event.repository.name }}
run: |
revisions=()

# Build the initial structure for the HTML table including the header row.
table="<table><thead><tr><th>CPU Architecture</th><th>Revision</th></tr></thead><tbody>"

# If we were able to fetch build manifests from previous step, use those
if ls -l manifest-*.yaml &>/dev/null; then
echo "Found build manifests - populating template with revisions from the manifests"

# Iterate over the manifest files and write the table rows for each architecture
for file in $(ls manifest-*.yaml); do
# Parse the arch and the revision
arch="$(cat "${file}" | yq -r '.architecture')"
rev="$(cat "${file}" | yq -r '.revision')"
# Write the table row and add the revision to the list we're tracking
table="${table}<tr><td>${arch}</td><td>${rev}</td></tr>"
revisions+=("$rev")
done
else
echo "No build manifests found - populating template with information from the store"

# Otherwise, get the latest revision for each architecture in the release channel
for arch in ${{ inputs.architectures }}; do
rev="$(snapcraft list-revisions "${SNAP_NAME}" --arch "$arch" | grep "latest/${{ inputs.channel }}*" | head -n1 | cut -d' ' -f1)"
revisions+=("$rev")
# Add a row to the HTML table
table="${table}<tr><td>${arch}</td><td>${rev}</td></tr>"
done
fi

# Add the closing tags for the table
table="${table}</tbody></table>"

# Get a comma separated list of revisions
printf -v joined '%s,' "${revisions[@]}"

version="$(cat snap/snapcraft.yaml | yq -r '.version')"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "revisions=${joined%,}" >> "$GITHUB_OUTPUT"
echo "table=${table}" >> "$GITHUB_OUTPUT"

- name: Fetch the call for testing template
shell: bash
run: |
wget -qO template.md "https://raw.githubusercontent.com/${{ inputs.ci-repo }}/main/call-for-testing/template.md"

- name: Create call for testing issue
uses: JasonEtco/create-an-issue@v2
id: issue
env:
GITHUB_TOKEN: ${{ inputs.github-token }}
snap_name: ${{ github.event.repository.name }}
channel: ${{ inputs.channel }}
revisions: ${{ steps.build.outputs.revisions }}
table: ${{ steps.build.outputs.table }}
version: ${{ steps.build.outputs.version }}
with:
filename: ./template.md
44 changes: 44 additions & 0 deletions call-for-testing/template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: Call for testing `{{ env.snap_name }}`
labels: testing
---

A new version ({{ env.version }}) of `{{ env.snap_name }}` was just pushed to the `{{ env.channel }}` channel [in the snap store](https://snapcraft.io/{{ env.snap_name }}). The following revisions are available.

{{ env.table }}

## Automated screenshots

The snap will be installed in a VM automatically; screenshots will be posted as a comment on this issue shortly.

## How to test it manually

1. Stop the application if it was already running
1. Upgrade to this version by running

```shell
snap refresh {{ env.snap_name }} --{{ env.channel }}
```

1. Start the app and test it out.
1. Finally, add a comment below explaining whether this app is working, and **include the output of the following command**.

```shell
snap version; lscpu | grep Architecture; snap info {{ env.snap_name }} | grep installed
```

## How to release it

Maintainers can promote this to stable by commenting `/promote <rev>[,<rev>] stable [done]`.

> For example
>
> - To promote a single revision, run `/promote <rev> stable`
> - To promote multiple revisions, run `/promote <rev>,<rev> stable`
> - To promote a revision and close the issue, run `/promote <rev>,<rev> stable done`

You can promote all revisions that were just built with:

```
/promote {{ env.revisions }} stable done
```
34 changes: 34 additions & 0 deletions get-architectures/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# snapcrafters/ci/get-architectures

Parses a `snapcraft.yaml` and returns the list of architectures supported both as a JSON array, and
a space-separated string.

## Usage

```yaml
# ...
jobs:
get-architectures:
name: 🖥 Get snap architectures
runs-on: ubuntu-latest
outputs:
architectures: ${{ steps.get-architectures.outputs.architectures }}
architectures-list: ${{ steps.get-architectures.outputs.architectures-list }}
steps:
- name: 🖥 Get snap architectures
id: get-architectures
uses: snapcrafters/ci/get-architectures@main
```

## API

### Inputs

None

### Outputs

| Key | Description | Example |
| -------------------- | -------------------------------------------------------------- | ------------------- |
| `architectures` | A space-separated list of architectures supported by the snap. | `amd64 arm64` |
| `architectures-list` | A JSON list of architectures supported by the snap | `["amd64" "arm64"]` |
jnsgruk marked this conversation as resolved.
Show resolved Hide resolved
39 changes: 39 additions & 0 deletions get-architectures/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Get Architectures
description: Get the architectures supported by a given snap
author: Snapcrafters
branding:
icon: code
color: orange

outputs:
architectures:
description: "A space-separated list of architectures supported by the snap"
value: ${{ steps.architectures.outputs.architectures }}
architectures-list:
description: "A JSON list of architectures supported by the snap"
value: ${{ steps.architectures.outputs.architectures_list }}

runs:
using: composite
steps:
- name: Checkout the source
uses: actions/checkout@v4

- name: Compute architectures
id: architectures
shell: bash
run: |
# Get the list as a json array. E.g. ["amd64", "arm64"]
architectures_list="$(cat snap/snapcraft.yaml | yq -r -I=0 -o=json '[.architectures[]]')"

# Get the list as a space-separated string. E.g. "amd64" "arm64"
architectures="$(cat snap/snapcraft.yaml | yq -r -I=0 -o=csv '[.architectures[]]' | tr ',' ' ')"

# Handle the case where architectures is a list of objects
if echo "$architectures" | grep -q "build-on"; then
architectures_list="$(cat snap/snapcraft.yaml | yq -r -I=0 -o=json '[.architectures[]."build-on"]')"
architectures="$(cat snap/snapcraft.yaml | yq -r -I=0 -o=csv '[.architectures[]."build-on"]' | tr ',' ' ')"
fi

echo "architectures_list=$architectures_list" >> "$GITHUB_OUTPUT"
echo "architectures=$architectures" >> "$GITHUB_OUTPUT"
44 changes: 44 additions & 0 deletions get-screenshots/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# snapcrafters/ci/get-screenshots

Deploys the snap from `latest/candidate` in a LXD desktop VM, then takes screenshots of the whole
desktop, and the most recent active window after the snap was launched. Screenshots are then
committed to [ci-screenshots](https://github.com/snapcrafters/ci-screenshots), and added to a comment on
the original call for testing issue.

## Usage

```yaml
# ...
jobs:
screenshots:
name: 📸 Gather screenshots
needs: call-for-testing
runs-on: ubuntu-latest
steps:
- name: 📸 Gather screenshots
uses: snapcrafters/ci/get-screenshots@main
with:
issue-number: ${{ needs.call-for-testing.outputs.issue-number }}
github-token: ${{ secrets.GITHUB_TOKEN }}
screenshots-token: ${{ secrets.SCREENSHOT_COMMIT_TOKEN }}
```

## API

### Inputs

| Key | Description | Required | Default |
| ------------------- | ------------------------------------------------------------------------------------------------------------------ | :------: | :---------------------------- |
| `issue-number` | The issue number to post the screenshots to. | Y | |
| `ci-repo` | The repo to fetch tools/templates from. Only for debugging. | N | `snapcrafters/ci` |
| `channel` | The channel to create the call for testing for. | N | `candidate` |
| `github-token` | A token with permissions to common on issues in the repository. | Y | |
| `screenshots-repo` | The repository where screenshots should be uploaded. | N | `snapcrafters/ci-screenshots` |
| `screesnhots-token` | A token with permissions to commit screenshots to [ci-screenshots](https://github.com/snapcrafters/ci-screenshots) | Y | |
jnsgruk marked this conversation as resolved.
Show resolved Hide resolved

### Outputs

| Key | Description | Example |
| -------- | ------------------------------------------------------------- | ------- |
| `screen` | A URL pointing to a screenshot of the whole screen in the VM | `12` |
jnsgruk marked this conversation as resolved.
Show resolved Hide resolved
| `window` | A URL pointing to a screenshot of the active window in the VM | `12` |
Loading