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

Add gitea support #759

Merged
merged 26 commits into from Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0c51329
Add new config option `[gitea]`
siblingsofthevoid Jan 3, 2024
3e586ea
tests: Create tests to generate config with gitea section
siblingsofthevoid Jan 3, 2024
0167c1c
Refactor integrations::github to share types with other integrations
siblingsofthevoid Jan 3, 2024
edaf160
Add Gitea API integration
siblingsofthevoid Jan 3, 2024
2157954
Add Gitea integration to CreatePullRequest step
siblingsofthevoid Jan 4, 2024
6034ccd
Add Gitea integration to Release step
siblingsofthevoid Jan 4, 2024
beb7e87
tests: Add tests to test Gitea Release
siblingsofthevoid Jan 4, 2024
b094edb
Add new SelectGiteaIssue step
siblingsofthevoid Jan 4, 2024
ea4e22d
docs: Add new Documentation and update existing docs to include Gitea
siblingsofthevoid Jan 4, 2024
38e24e5
ci(vale): Add Gitea and Codeberg to accepted Vale vocabulary
siblingsofthevoid Jan 4, 2024
9bc0104
chore: Create Changeset for Gitea Integration
siblingsofthevoid Jan 4, 2024
c6826dd
Fix changeset
siblingsofthevoid Jan 12, 2024
2cc1bfb
Fix docs
siblingsofthevoid Jan 12, 2024
3b9f550
Fix dry run messages on Release
siblingsofthevoid Jan 12, 2024
7a42f4b
Fix tests
siblingsofthevoid Jan 12, 2024
ada7794
Make sure to warn about package assets support in gitea
siblingsofthevoid Jan 12, 2024
bb71563
Make sure to warn the user that a PR will be created on all forges if…
siblingsofthevoid Jan 12, 2024
ad86c3d
Fix dry run message in SelectIssue step
siblingsofthevoid Jan 12, 2024
0e357af
Fix docstring for SelectGiteaIssue step
siblingsofthevoid Jan 12, 2024
30147a4
Add tests to check if multi forge releases work
siblingsofthevoid Jan 12, 2024
a4fe93d
Merge branch 'main' into add_gitea_support
dbanty Jan 12, 2024
78b332b
docs: Some tweaks to make Vale happy
dbanty Jan 13, 2024
cf5ee72
Enforce that Gitea + assets aren't both declared.
dbanty Jan 13, 2024
d7f535b
Slightly better binary expression
dbanty Jan 13, 2024
9e79f07
Fix some GitHub copy pasta
dbanty Jan 13, 2024
38383ae
Attribution 😁
dbanty Jan 13, 2024
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
31 changes: 31 additions & 0 deletions .changeset/gitea_support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
default: minor
---

# Gitea support

PR #759 closed issue #743. Thank you, @FallenValkyrie!

- Added Support for Gitea in the `CreatePullRequest` step
- Added Support for Gitea in the `Release` step
- Added A new `SelectGiteaIssue` step
- Add support to generate Gitea config from known public Gitea instances

## How it works

To be able to use these new steps, just add a new section to your configuration, like this:

```toml
[gitea]
repo = "knope"
owner = "knope-dev"
host = "https://codeberg.org"
```

You can now use the supported steps in the same way as their GitHub equivalents.

## Generating a configuration

Knope can now generate a configuration for you, if your repository's remote is one of the known
public Gitea instances. Currently only [Codeberg](https://codeberg.org) is supported,

Check warning on line 30 in .changeset/gitea_support.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.Passive] 'is supported' looks like passive voice. Raw Output: {"message": "[Microsoft.Passive] 'is supported' looks like passive voice.", "location": {"path": ".changeset/gitea_support.md", "range": {"start": {"line": 30, "column": 73}}}, "severity": "INFO"}
but feel free to add more [here](https://github.com/knope-dev/knope/blob/main/src/config/toml/config.rs#L90).
2 changes: 2 additions & 0 deletions .github/vale/config/vocabularies/Custom/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ GitHub Actions
musl
TOML
rebasing
Gitea
Codeberg
17 changes: 17 additions & 0 deletions docs/src/content/docs/reference/Concepts/forge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: "Forge"
---

A forge is a fully featured Git server with a web interface, like GitHub, Gitea or GitLab.
Currently Knope can interact with the following forges:

- [Gitea]
- [GitHub]

:::caution
If you configure more than one forge, Knope will assume that you wish to push to all of them.

Check warning on line 12 in docs/src/content/docs/reference/Concepts/forge.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.Wordiness] Consider using 'all' instead of 'all of'. Raw Output: {"message": "[Microsoft.Wordiness] Consider using 'all' instead of 'all of'.", "location": {"path": "docs/src/content/docs/reference/Concepts/forge.md", "range": {"start": {"line": 12, "column": 82}}}, "severity": "WARNING"}
Keep that in mind, when writing your configuration.
:::

[Gitea]: /reference/config-file/gitea
[GitHub]: /reference/config-file/github
2 changes: 1 addition & 1 deletion docs/src/content/docs/reference/Concepts/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
2. Update all versioned files with the new version
3. Add the details of all changes since the last release to the [changelog]
4. Create a [Git tag](#git-tags)
5. Optionally create a GitHub release (as part of the previous step) if [GitHub is configured](/reference/config-file/github)
5. Optionally create a release (as part of the previous step) if [a forge is configured](/reference/concepts/forge)

Check warning on line 13 in docs/src/content/docs/reference/Concepts/release.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.ComplexWords] Consider using 'earlier' instead of 'previous'. Raw Output: {"message": "[Microsoft.ComplexWords] Consider using 'earlier' instead of 'previous'.", "location": {"path": "docs/src/content/docs/reference/Concepts/release.md", "range": {"start": {"line": 13, "column": 48}}}, "severity": "INFO"}

Check warning on line 13 in docs/src/content/docs/reference/Concepts/release.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.Passive] 'is configured' looks like passive voice. Raw Output: {"message": "[Microsoft.Passive] 'is configured' looks like passive voice.", "location": {"path": "docs/src/content/docs/reference/Concepts/release.md", "range": {"start": {"line": 13, "column": 75}}}, "severity": "INFO"}

:::tip

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@
title: CreatePullRequest
---

Create a pull request on GitHub from the current branch to a specified branch. If a pull request for those already exists, this step will overwrite the title and body of the existing pull request.
Create a pull request on every configured forge from the current branch to a specified branch. If a pull request for those already exists, this step will overwrite the title and body of the existing pull request.

:::caution
If you configure more than one forge, Knope will assume that you wish to create a PR on all of them.

Check warning on line 8 in docs/src/content/docs/reference/Config File/Steps/create-pull-request.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.Wordiness] Consider using 'all' instead of 'all of'. Raw Output: {"message": "[Microsoft.Wordiness] Consider using 'all' instead of 'all of'.", "location": {"path": "docs/src/content/docs/reference/Config File/Steps/create-pull-request.md", "range": {"start": {"line": 8, "column": 89}}}, "severity": "WARNING"}
Keep that in mind, when writing your configuration.
:::

## Prerequisites

To use the `CreatePullRequest` step, you must configure a forge first. See [configuring a Forge] for more information.

## Parameters

Expand Down Expand Up @@ -52,3 +61,4 @@

[Knope's prepare-release workflow]: https://github.com/knope-dev/knope/blob/e7292fa746fe1d81b84e5848815c02a0d8fc6f95/.github/workflows/prepare_release.yml
[knope's release workflow]: https://github.com/knope-dev/knope/blob/e7292fa746fe1d81b84e5848815c02a0d8fc6f95/.github/workflows/release.yml
[configuring a forge]: /reference/concepts/forge
27 changes: 16 additions & 11 deletions docs/src/content/docs/reference/Config File/Steps/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
---

Release the configured [packages] which have pending changes.
If there is a [GitHub config] set,
this creates a release on GitHub with the same release notes that it added to the changelog (if any).
If there is a [forge config] set,
This conversation was marked as resolved.
Show resolved Hide resolved
this creates a release with the same release notes that it added to the changelog (if any).
Otherwise, this tags the current commit as a release.
In either case, this step adds a new Git tag with the package's tag format.
You should run [`PrepareRelease`] before this step, though not necessarily in the same workflow.
Expand All @@ -21,15 +21,15 @@
each package gets its own tag in the format `{name}/v{version}` (this is the syntax required for Go modules).
See examples below for more illustration.

## GitHub release notes
## Release notes

There are several different possible release notes formats:

1. If run after a [`PrepareRelease`] step in the same workflow, the release notes will be the same as the changelog section created by [`PrepareRelease`] even if there is no changelog file configured—with the exception that headers are one level higher (for example, `####` becomes `###`).
2. If run in a workflow with no [`PrepareRelease`] step before it (the new version was set another way), and there is a changelog file for the package, the release notes will be taken from the relevant changelog section. This section header must match exactly what [`PrepareRelease`] would have created. Headers will one level higher (for example, `####` becomes `###`).
3. If run in a workflow with no [`PrepareRelease`] step before it (the new version was set another way), and there is no changelog file for the package, the step will use GitHub's automatic release notes generation.
3. If run in a workflow with no [`PrepareRelease`] step before it (the new version was set another way), and there is no changelog file for the package, the step will use automatic release notes generation.

Check warning on line 30 in docs/src/content/docs/reference/Config File/Steps/release.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.Passive] 'was set' looks like passive voice. Raw Output: {"message": "[Microsoft.Passive] 'was set' looks like passive voice.", "location": {"path": "docs/src/content/docs/reference/Config File/Steps/release.md", "range": {"start": {"line": 30, "column": 84}}}, "severity": "INFO"}

## GitHub release assets
## Release assets

You can optionally include any number of assets to include in a release via [package assets].
If you do this, this step will:
Expand All @@ -42,15 +42,20 @@
you can use `on: release: created` to run as soon as the step creates the draft
(without assets) or `on: release: published` to run only after the assets are uploaded.

:::caution
[Package assets] are currently unsupported when used together with Gitea.
This is due to one of Knope's dependencies not supporting `multipart/form-data` requests.
:::

## Errors

This step will fail if:

1. [GitHub config] exists but Knope can't create a release on GitHub. For example:
1. There is no GitHub token set.
2. The GitHub token doesn't have permission to create releases.
3. The release already exists on GitHub (causing a conflict).
2. There is no [GitHub config] set and Knope can't tag the current commit as a release.
1. [forge config] exists but Knope can't create a release on the forge. For example:
1. There is no token set.
2. The token doesn't have permission to create releases.
3. The release already exists on the forge (causing a conflict).
2. There is no [forge config] set and Knope can't tag the current commit as a release.
3. Could not find the correct changelog section in the configured changelog file for loading release notes.
4. One of the configured package assets doesn't exist.

Expand Down Expand Up @@ -179,7 +184,7 @@
3. Fan out into several jobs which each check out the changes and build a different binary
4. Create a GitHub release with the new version, changelog, and the binary assets

[github config]: /reference/config-file/github
[forge config]: /reference/concepts/forge
[`preparerelease`]: /reference/config-file/steps/prepare-release
[packages]: /reference/concepts/package
[package assets]: /reference/config-file/packages#assets
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: SelectGiteaIssue
---

Search for Gitea issues by status and display the list of them in the terminal.
Selecting an issue enables other steps to use the issue's information (for example, [`SwitchBranches`]).

## Errors

This step will fail if any of the following are true:

1. Knope can't communicate with the Gitea instance.
2. There is no [Gitea config] set.
3. User doesn't select an issue.

## Example

```toml
[[workflows]]
name = "Start some work"
[[workflows.steps]]
type = "SelectGiteaIssue"
label = "selected"
```

[Gitea config]: /reference/config-file/gitea
[`switchbranches`]: /reference/config-file/steps/switch-branches
20 changes: 20 additions & 0 deletions docs/src/content/docs/reference/Config File/gitea.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: "Gitea"
---

Details needed to use steps that reference Gitea repositories.

## Example

```toml
# knope.toml

[gitea]
owner = "knope-dev"
repo = "knope"
host = "https://codeberg.org"
```

The first time you use a step which requires this config,
you will be prompted to generate a Gitea API token so Knope can perform actions on your behalf.

Check warning on line 19 in docs/src/content/docs/reference/Config File/gitea.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Microsoft.Passive] 'be prompted' looks like passive voice. Raw Output: {"message": "[Microsoft.Passive] 'be prompted' looks like passive voice.", "location": {"path": "docs/src/content/docs/reference/Config File/gitea.md", "range": {"start": {"line": 19, "column": 10}}}, "severity": "INFO"}
To bypass this prompt, you can manually set the `GITEA_TOKEN` environment variable.
4 changes: 4 additions & 0 deletions docs/src/content/docs/reference/Config File/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ Assets is a list of files to upload to a GitHub release. They do nothing without
Assets are per-package. Each asset can optionally have a `name`, this is what it will appear as in GitHub releases.
The `name` defaults to the final part of the path.

:::caution
Knope doesn't yet support uploading assets to Gitea, declaring both `[gitea]` and assets is an error.
:::

```toml
[package]

Expand Down
13 changes: 13 additions & 0 deletions src/app_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ pub(crate) fn get_or_prompt_for_github_token() -> Result<String, Error> {
})
}

pub(crate) fn get_or_prompt_for_gitea_token(host: &str) -> Result<String, Error> {
std::env::var("GITEA_TOKEN").or_else(|_| {
let prompt = format!(
"\
No Gitea token found, generate one from {host}/user/settings/applications with\n\
`repository` permissions set to `Read and Write`\
and `issue` permissions set to `Read` and input here\
"
);
load_value_or_prompt("gitea_token", &prompt)
})
}

pub(crate) fn load_value_or_prompt(key: &str, prompt: &str) -> Result<String, Error> {
let app_dirs = AppDirs::new(Some("knope"), true).ok_or(Error::CouldNotOpenConfigPath)?;
let config_path = app_dirs.config_dir.join(key);
Expand Down
73 changes: 68 additions & 5 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ use crate::{

pub(crate) mod toml;

pub(crate) use self::toml::{ChangeLogSectionName, CommitFooter, CustomChangeType, GitHub, Jira};
pub(crate) use self::toml::{
ChangeLogSectionName, CommitFooter, CustomChangeType, GitHub, Gitea, Jira,
};

/// A valid config, loaded from a supported file (or detected via default)
#[derive(Debug)]
Expand All @@ -31,6 +33,8 @@ pub(crate) struct Config {
pub(crate) jira: Option<Jira>,
/// Optional configuration to talk to GitHub
pub(crate) github: Option<GitHub>,
/// Optional configuration to communicate with a Gitea instance
pub(crate) gitea: Option<Gitea>,
}

impl Config {
Expand Down Expand Up @@ -65,12 +69,14 @@ impl Config {
package: Option<toml::Package>,
workflows: Vec<Workflow>,
github: Option<GitHub>,
gitea: Option<Gitea>,
}

let config = SimpleConfig {
package: self.packages.pop().map(toml::Package::from),
workflows: self.workflows,
github: self.github,
gitea: self.gitea,
};
#[allow(clippy::unwrap_used)] // because serde is annoying... I know it will serialize
let serialized = to_string(&config).unwrap();
Expand Down Expand Up @@ -123,6 +129,18 @@ impl TryFrom<(ConfigLoader, String)> for Config {
.collect::<Result<Vec<Package>, Error>>()?,
(None, None) => Vec::new(),
};

if config.gitea.is_some()
&& packages.iter().any(|package| {
package
.assets
.as_ref()
.is_some_and(|assets| !assets.is_empty())
})
{
return Err(Error::GiteaAssetUploads);
}

Ok(Self {
packages,
workflows: config
Expand All @@ -133,6 +151,7 @@ impl TryFrom<(ConfigLoader, String)> for Config {
.collect(),
jira: config.jira.map(Spanned::into_inner),
github: config.github.map(Spanned::into_inner),
gitea: config.gitea.map(Spanned::into_inner),
})
}
}
Expand Down Expand Up @@ -196,10 +215,17 @@ pub(crate) enum Error {
url("https://knope.tech/reference/config-file/packages/")
)]
EmptyPackages,
#[error("Asset uploads for Gitea are not supported")]
#[diagnostic(
code(config::gitea_asset_uploads),
help("Remove the `[[package.assets]]` key from your config."),
url("https://github.com/knope-dev/knope/issues/779")
)]
GiteaAssetUploads,
}

#[cfg(test)]
mod test_package_configs {
mod test_errors {

use super::Config;

Expand All @@ -219,15 +245,39 @@ mod test_package_configs {
let config = Config::try_from((config, toml_string));
assert!(config.is_err(), "Expected an error, got {config:?}");
}

#[test]
fn gitea_asset_error() {
let toml_string = r#"
[packages.something]
[[packages.something.assets]]
name = "something"
path = "something"
[[workflows]]
name = "default"
[[workflows.steps]]
type = "Command"
command = "echo this is nothing, really"
[gitea]
host = "https://gitea.example.com"
owner = "knope"
repo = "knope"
"#
.to_string();
let config: super::toml::ConfigLoader = toml::from_str(&toml_string).unwrap();
let config = Config::try_from((config, toml_string));
assert!(config.is_err(), "Expected an error, got {config:?}");
}
}

/// Generate a brand new Config for the project in the current directory.
pub(crate) fn generate() -> Config {
let mut variables = IndexMap::new();
variables.insert(String::from("$version"), Variable::Version);

let github = match git::get_first_remote() {
Some(remote) if remote.contains("github.com") => {
let first_remote = git::get_first_remote();
let github = match first_remote {
Some(ref remote) if remote.contains("github.com") => {
let parts = remote.split('/').collect::<Vec<_>>();
let owner = parts.get(parts.len() - 2).map(|owner| {
owner
Expand All @@ -246,7 +296,19 @@ pub(crate) fn generate() -> Config {
}
_ => None,
};
let mut release_steps = if github.is_some() {

let gitea = first_remote.as_ref().and_then(|remote| {
if Gitea::KNOWN_PUBLIC_GITEA_HOSTS
.iter()
.any(|known_host| remote.contains(known_host))
{
Gitea::try_from_remote(remote)
} else {
None
}
});

let mut release_steps = if github.is_some() || gitea.is_some() {
vec![
Step::Command {
command: String::from(
Expand Down Expand Up @@ -284,6 +346,7 @@ pub(crate) fn generate() -> Config {
],
jira: None,
github,
gitea,
packages: find_packages().ok().into_iter().collect(),
}
}
Loading